使用LINQ to XML时避免暴露于NullReferenceException

时间:2010-11-28 06:53:40

标签: c# .net linq-to-xml

我正在使用对XElement.Element()方法的一系列调用来深入研究XML文档并提取属性的值:

XElement root = ...;
XNamespace ns = "...";
var firstName = 
  root
    .Element(ns + "Employee")
    .Element(ns + "Identity")
    .Element(ns + "Name")
    .Attribute(ns + "FirstName");

但是,由于传入文档尚未经过模式验证,如果任何预期的中间元素不存在,则格式错误的文档可能会导致NullReferenceException

有没有办法避免这种风险,同时保持代码简洁?

我可以将上面的代码包装在NullReferenceException的处理程序中但是这感觉不对,并且也没有具体指出失败发生的位置。构建信息性错误消息将是手动,繁琐,容易出错和维护危险。

我是否应该使用XPath,这样我可以检查null返回,然后轻松构造一条错误消息,指示XPath表达式无法解析?

2 个答案:

答案 0 :(得分:7)

一种选择是使用Elements()而不是Element() - 如果找不到该元素,将产生一个空序列。使用Extensions中的扩展方法,您可以从元素序列元素序列 - 对于属性也是如此。所以:

var firstName = 
  root
    .Elements(ns + "Employee")
    .Elements(ns + "Identity")
    .Elements(ns + "Name")
    .Attributes(ns + "FirstName")
    .FirstOrDefault();

两个片段之间存在差异,请注意 - 这将找到第一个匹配属性,即使它来自(比如说)第二个Employee中第三个Identity元素中的第一个Name元素元件。这对您来说可能是也可能不是问题。

(只是为了检查,你肯定需要属性上的命名空间吗?与元素不同,属性不会继承“默认”命名空间。在命名空间上使用属性比在元素上使用属性更少。)

答案 1 :(得分:1)

您可以定义en extension方法来包装空值检测。像这样的东西,例如:

public static class XmlExtender
{
   public static XAttribute AttributeOrDefault(this XElement el, XName name, string defValue)
   {
      var v = el.Attribute(name);
      return v == null ? new XAttribute(name, defValue) : v;
   }

   public static string AttributeValue(this XElement el, XName name, string defValue)
   {
      var v = el.Attribute(name);
      return v == null ? defValue : v.Value;
   }
}

然后可以像这样使用:

var firstName = root.ELement("elname")
                    .AttributeOrDefault("attrName", "N/A").Value;

或者这个:

var firstName = root.Element("elname")
                    .AttributeValue("attrName", "N/A");