在LINQ中使用let时,如何处理缺少的XML节点?

时间:2016-01-08 21:29:41

标签: c# xml linq

我有一个非常大的XML文档,它有一些缺少的节点。

良好的XML:

<wd:Job_Family wd:Descriptor="Research/Extension">
<wd:Home_Phone wd:Descriptor="+1 (555) 555-0731">
  <wd:ID wd:type="WID">89bfac800b6b41da94e1d1a22b14e66a</wd:ID>
</wd:Home_Phone>
<wd:Home_Address wd:Descriptor="1 Beverly Dr">

错误的XML:

 <wd:Job_Family wd:Descriptor="Research/Extension">
     ***MISSING ***
<wd:Home_Address wd:Descriptor="1 Beverly Dr">

我选择数据的方式是这样的:

List<Employee> employee = new List<Employee>();
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<XElement> 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;

这很有效。我选择了一些额外的节点,但为了简单起见,这就足够了。

现在,当我尝试选择缺少的节点(可能是1000条记录中的1条)时,我得到的Object引用错误未设置为对象的实例。

这是有道理的,因为被选中的节点不在那里。 阅读了很多帖子之后,看起来我应该做一个三元运算符来解释null父级。像这样:

let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? "" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault()

这不是很正确: 无法确定条件表达式的类型,因为&#39; string&#39;之间没有隐式转换。和&#39; System.Xml.Linq.XAttribute&#39;

即使我将它转换为字符串或对象,它也会编译,但是当我添加范围时,我只获得所有记录的第一个值:

let homePhoneAttribute = x.Element(wd + "Home_Phone") == null ? (string)"" : x.Element(wd + "Home_Phone").Attributes(wd + "Descriptor").FirstOrDefault().Value

所以,我啰嗦的问题是,我如何正确地投射和计算空节点,同时仍然能够选择一个让?

我认为它必须是某种DefaultIfEmpty()投射?

1 个答案:

答案 0 :(得分:1)

您可以使用以下表达式:

let homePhoneAttribute = (string)x.Elements(wd + "Home_Phone")
                                  .Attributes(wd + "Descriptor")
                                  .FirstOrDefault()

使用x.Elements()代替单数形式Element(),可以避免在找不到元素时出现异常。然后,通过将FirstOrDefault()返回值转换为string,如果返回值为null,则可以避免异常。

<强> dotnetfiddle demo

该演示显示,当homePhoneAttribute元素缺失时,wd:Home_Phone变量只包含空字符串。没有例外。

更新:

如果你想要多个属性值(List<string>)而不仅仅是第一个,你可以修改上面的LINQ,如下所示:

let homePhoneAttribute = x.Elements(wd + "Home_Phone")
                          .Attributes(wd + "Descriptor")
                          .Select(o => o.Value)
                          .ToList()