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

时间:2012-08-06 15:43:47

标签: c# linq linq-to-xml

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

问题出在“城市”一行。城市房产的数据来自xml结构前景/ contactinfo / City / Answer。

但由于该字段不是强制性的,因此有时XML不会有城市/答案节点。所以我得到错误,因为“city”节点不存在,我正试图在其上调用“.Element()”。我找到了很多解决这个问题的方法,当它只有一个节点级别的时候(即如果我需要的数据是在城市,而城市是唯一缺少的节点)。

但是当它降低两级时(即尝试获取一个不存在的节点的子节点),我找不到任何解决方案。

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

祝你好运, 的Morten

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

3 个答案:

答案 0 :(得分:5)

一种选择是使用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”,然后是“ab”,然后是“abc”等),然后是真正的“取物”,而在此方案中,您只需为每个新导航链接添加一个Elements次呼叫。

答案 1 :(得分:2)

如果任何节点可以为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建议)是保持代码清洁的好方法。这也意味着你可以很容易地延长支票。

答案 2 :(得分:1)

我创建了一个泛型函数来获取您使用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();

注意:这是未经测试的代码,但提供了一般的想法。您可能必须在函数中包含其他参数,以指定是否要在元素上调用'.Value'或其他方法。