使用 LINQ to XML 时避免暴露 NullReferenceException

发布于 2024-10-05 12:54:52 字数 654 浏览 3 评论 0原文

我正在使用对 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 来代替,这样我就可以检查空返回,然后轻松构造一个错误消息表明无法解析 XPath 表达式?

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 incoming 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

并安 2024-10-12 12:54:52

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

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

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

(只是检查一下,您确实需要属性上的命名空间吗?与元素不同,属性不会继承“默认”命名空间。在命名空间上使用属性比在元素上使用属性更罕见。)

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.)

终止放荡 2024-10-12 12:54:52

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

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");

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");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文