LinQ to xml,指定任何时候都可以为null的路由

时间:2017-06-28 11:39:53

标签: c# xml linq

<b>
  <c>
     <z> Wally  </z>
     <w> whatever </w>  
  </c>
  <d>
     <z> anotherValue </z>
  </d>
  <e> idValue </e>
</b>


class Example {
  public string Id {get; set;}
  public string name {get; set;}
}

假设我们有上面的xml和类。我试图使用LinQ到Xml从xml创建一个对象。

我可以通过以下方式实现这一目标:

var doc = XDocument.Load(xmlPath);
var root = doc.Root;

var anExample = new Example()
{
   Id = root.Element("e").Value,
   name = root.Element("c").Element("z").Value
};

到目前为止,问题是'c'和'z'标签是可选的。你可以没有'c'或'c'没有'z'。 然后我会发现自己检查每个标记是否为null,以避免在null对象上调用Element方法和Value属性。 我的意思是:

var doc = XDocument.Load(xmlPath);
var root = doc.Root;

var anExample = new Example(){ Id = root.Element("e").Value };

var c = root.Element("c")

if(c != null) {
   var z = c.Element("z");
   if( z != null)
    anExample.name = z.Value;
}

随着嵌套级别的增加,事情变得更糟。我想大多数人都有更好的方式去做我想做的事。

2 个答案:

答案 0 :(得分:1)

您可以使用C# 6.0 null-conditional operator确保调用链中的所有项都不为空:

// C# 6 or higher:
string value = doc.Root?.Element("c")?.Element("z")?.Value;

如果仅存在所有给定元素,则此表达式的结果将具有值,否则将为null

另一种方法是使用System.Xml.XPath命名空间中的XPath扩展方法来查找元素。如果您使用C#6甚至更旧版本更合适,因为它没有空条件运算符看起来很好:

// C# 6 or higher:
string value = doc.Root.XPathSelectElement("./c/z")?.Value;

// C# 5 or lower:
var element = doc.Root.XPathSelectElement("./c/z");
if (element != null)
{
    string value = element.Value;
}

结果将是相同的,因为如果元素不存在,XPathSelectElement将返回null

答案 1 :(得分:0)

你应该尝试留在IEnumerable的LINQ世界,直到最后一刻。

这意味着使用Elements而不是Element - 如果元素丢失,这将返回一个空序列。

最后,您可以调用SingleOrDefault来获取结果元素,如果缺少其中一个元素,则可以调用null。

请注意,explicit conversion operators可以将元素转换为各种类型 - 当您需要转换为string之外的其他内容时,这可能很有用,并且还可以处理元素为null的情况。

var name = (string) root.Elements("c").Elements("z").SingleOrDefault()