开发者

Avoiding exposure to NullReferenceException when using LINQ to XML

I am using a chain of calls to the XElement.Element() method to drill down into an XML document and pull out the value of an attribute:

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

However, since the i开发者_如何学运维ncoming document has not been schema validated it is possible that a malformed document will cause a NullReferenceException if any of the expected intermediate elements does not exist.

Is there a way to avoid this risk, whilst keeping the code succinct?

I can wrap the code above in a handler for NullReferenceException however this feels wrong, and would also not specifically indicate where the failure occurred. Constructing an informative error message would be manual, tedious, error prone, and a maintenance hazard.

Should I be using XPath instead, that way I can check for a null return and then easily construct an error message indicating that the XPath expression could not be resolved?


One option is to use Elements() instead of Element() - which will yield an empty sequence if the element isn't found. Using the extension methods in Extensions, you can go from a sequence of elements to a sequence of elements - and the same for attributes. So:

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

There is a difference between the two snippets, mind you - this will find the first matching attribute even if it comes from (say) the first Name element within the third Identity element within the second Employee element. That may or may not be an issue for you.

(Just to check, do you definitely need the namespace on the attribute? Unlike elements, attributes don't inherit a "default" namespace. It's rarer to use attributes on namespaces than on elements.)


You can define en extension method to wrap the null detection. Something like this, for instance:

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;
   }
}

which can then be used like this:

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

or this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜