“对象引用未设置为对象的实例”时尝试获取具有不存在父级的元素

本文关键字:获取 不存在 元素 设置 对象引用 对象 实例 | 更新日期: 2024-11-05 04:01:50

我最近开始使用Linq,我目前正在尝试使用它来解析一个高度嵌套的XML文件(我无法控制)。但是,在尝试运行以下语句时,我收到"对象引用未设置为对象的实例"错误。

问题出在"城市"行中。城市属性的数据来自 xml 结构 prospect/contactinfo/City/Answer。

但由于该字段不是必填字段,因此有时 XML 将没有城市/应答节点。所以我收到错误,因为"城市"节点不存在,我正在尝试调用".元素()"在上面。我已经找到了很多解决这个问题的解决方案,当它只有一个节点级别时(即,如果我需要的数据在城市中,而城市是唯一缺少的节点)。

但是当它向下两级时(即试图获取不存在节点的子节点),我无法找到任何解决方案。

希望这个问题表达得足够清楚。

此致敬意莫滕

            var prospects = (from prospect in xdoc.Descendants("PROSPECT")
                        select new Prospect {
                            ProspectID = (string) prospect.Element("PROSPECTINFO").Element("PROSPECT_ID"),
                            Name = (string) prospect.Element("PERSONALINFO").Element("FIRSTNAME")+ " " + prospect.Element("PERSONALINFO").Element("SURNAME"),
                            address = (string) prospect.Element("CONTACTINFO").Element("ADDRESSLINE1").Element("ANSWER"),
                            zipCode = (string)prospect.Element("CONTACTINFO").Element("POSTALCODE").Element("ANSWER").Value,
                            City = (string) prospect.Element("CONTACTINFO").Element("CITY").Element("ANSWER"),                                
                        }).ToList();

“对象引用未设置为对象的实例”时尝试获取具有不存在父级的元素

一种选择是使用 Elements 而不是 Element 。这是一种扩展方法,可在单个元素或元素集合中查找所有元素(可选具有给定名称)。因此,如果您重复使用它,如果没有任何匹配项,您最终会在末尾得到一个包含 0 个元素的集合。使用 FirstOrDefault 获取该元素或 null,然后字符串转换将执行所需的操作:

// Still use Element for CONTACTINFO as presumably that's a required element
City = (string) prospect.Element("CONTACTINFO")
                        .Elements("CITY")
                        .Elements("ANSWER")
                        .FirstOrDefault()

这样你就不必编写任何条件代码 - 一切都会消失。

与 ChrisF 建议的那种检查相比,这样做的最大优势是导航路径是否变长。想象一下,路径有 6 个部分,每个部分都是可选的 - 您需要 5 次检查(首先是"a",然后是"a.b",然后是"a.b.c"等),然后是真正的"获取东西",而在这个方案中,您只需为每个新的导航链接添加一个额外的Elements调用。

如果任何节点可以为 null,那么您必须在代码中处理它。

您提到了"CITY"节点,因此以它为例:

var prospects = (from prospect in xdoc.Descendants("PROSPECT")
                    select new Prospect {
                        ProspectID =
 (string)prospect.Element("PROSPECTINFO").Element("PROSPECT_ID"),
                        Name =
 (string)prospect.Element("PERSONALINFO").Element("FIRSTNAME")+ " " + prospect.Element("PERSONALINFO").Element("SURNAME"),
                        address =
 (string)prospect.Element("CONTACTINFO").Element("ADDRESSLINE1").Element("ANSWER"),
                        zipCode =
 (string)prospect.Element("CONTACTINFO").Element("POSTALCODE").Element("ANSWER").Value,
                        City =
 prospect.Element("CONTACTINFO").Element("CITY") != null ?
     (string)prospect.Element("CONTACTINFO").Element("CITY").Element("ANSWER") :
     string.Empty,
   }).ToList();

在尝试尊重元素之前,您需要检查元素是否为 null,如果为 null,请选择要分配给属性的默认值。

对所有可以为 null 的元素重复此操作。

将检查放入方法(如 Mike 建议的那样)是保持代码干净的好方法。这也意味着您可以非常轻松地扩展检查。

我会创建一个泛型函数来获取您使用 NULL 检查指定的任何元素的值。下面是一个示例:

public string GetXMLElementValue(XmlElement xElem, params string[] elementsNest)
{
    XmlElement tempElem = xElem;
    foreach (string s in elementsNest)
    {
        if (tempElem.Element(s) == null)
            return string.Empty;
        else
            tempElem = tempElem.Element(s);
    }
    return (string) tempElem;
}

然后你可以像这样使用它:

var prospects = (from prospect in xdoc.Descendants("PROSPECT")
    select new Prospect {
        . . .
        City = GetXMLElementValue(prospect, "CONTACTINFO", "CITY", "ANSWER"),          
}).ToList();

注意:这是未经测试的代码,但给出了一般的想法。您可能必须在函数中具有其他参数来指定是否要调用 '.元素上的值"或其他方法。