title: How do I handle missing XML nodes when working with let in LINQ?
body: <p>I have a very large XML document that has some missing nodes.</p>
  
  <p>Good XML:</p>
  
  <pre><code>&lt;wd:Job_Family wd:Descriptor="Research/Extension"&gt;
  &lt;wd:Home_Phone wd:Descriptor="+1 (555) 555-0731"&gt;
    &lt;wd:ID wd:type="WID"&gt;89bfac800b6b41da94e1d1a22b14e66a&lt;/wd:ID&gt;
  &lt;/wd:Home_Phone&gt;
  &lt;wd:Home_Address wd:Descriptor="1 Beverly Dr"&gt;
  </code></pre>
  
  <p>Bad XML:</p>
  
  <pre><code> &lt;wd:Job_Family wd:Descriptor="Research/Extension"&gt;
       ***MISSING ***
  &lt;wd:Home_Address wd:Descriptor="1 Beverly Dr"&gt;
  </code></pre>
  
  <p>The way I had been selecting the data was like this:</p>
  
  <pre><code>List&lt;Employee&gt; employee = new List&lt;Employee&gt;();
  try
  {
      // Get the xml file as stream  
      StreamReader reader = new StreamReader(outputFileNameAndPath);
  
      // Read the whole contents and return as a string  
      string xmlString = reader.ReadToEnd();
  
      XDocument doc = XDocument.Parse(xmlString);
      XNamespace wd = "urn:com.something.report/Worker_ID_Data_-_Store";
  
      IEnumerable&lt;XElement&gt; worker = doc.Descendants(wd + "Report_Entry");
  
      var query = (from x in doc.Descendants(wd + "Report_Entry")
  
                   let jobFamilyAttribute = x.Element(wd + "Job_Family_Group").Attributes(wd + "Descriptor").FirstOrDefault()
  
                   select new Employee
                   {
                      JobFamily = jobFamilyAttribute.Value
                   });
      employee.AddRange(query);
  }
  catch (Exception ex)
  {
      log.Error("An error occurred while trying to parse the XML: " + ex);
  }
  return employee;
  </code></pre>
  
  <p>That works great.  There are some additional nodes I select, but for simplicity sake, this is enough.</p>
  
  <p>Now, when I try to select a node that is missing (which might be 1 out of 1000 records), I get errors for Object reference not set to an instance of an object.  </p>
  
  <p>That makes sense, since the node being selected isn't there.
  After reading many postings, it looks like I should do a ternary operator to account for the null parent.  Something like this:</p>
  
  <pre><code>let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? "" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault()
  </code></pre>
  
  <p>That isn't quite right:
  Type of conditional expression cannot be determined because there is no implicit conversion between 'string' and 'System.Xml.Linq.XAttribute'</p>
  
  <p>Even if I cast it to a string or object, it compiles, but then I only get the very first value for all records when I addrange:</p>
  
  <pre><code>let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? (string)"" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault().Value
  </code></pre>
  
  <p>So, my long winded question is, how do I properly cast and account for null nodes while still being able to select with a let?</p>
  
  <p>I think it has to be some kind of <code>DefaultIfEmpty()</code> casting?</p>