我最近遇到了一种情况,我必须使用 XPath 作为 Linq to XML 查询的一部分,发现它的行为有点奇怪。我确信还有其他方法可以使用本机 XElement API 方法解决问题,但在这种情况下,XPath 更适合定位我需要的特定 XML 文本值,因为文档结构非常复杂。我最终找到了一种让它工作的方法(见下文),但它不是很漂亮,这通常意味着我错过了一些东西。
我的问题是如何使用XPathEvalute或其他一些 XPath 方法返回一个字符串值,该字符串值可以在 where 语句中使用或作为 select 方法中新对象的一部分。我找到了一个在 LINQ 中使用大量强制转换和Null 合并运算符的解决方案,但必须有一种更清洁的方法。问题的根源在于 XPathEvaluate 方法通常会返回一个 XText 元素(强制转换为通用对象),但 Linq 将其转换为 IEnumerable 以便它可以延迟执行。当您尝试访问该对象的值时,这会导致问题,因为在执行查询之前它不会实现。
下面是示例: 使用以下 XML 文档查找所有拥有同名男孩和女孩的父母。这必须使用 XPath 查询来完成,因为在我的情况下,文档结构非常复杂。
//Use C# Program Language type in LinqPad
void Main()
{
var xml = XElement.Parse(@"<Root>
<Parent>
<Boy>Anne</Boy>
</Parent>
<Parent>
<Boy>Alex</Boy>
<Girl>Alex</Girl>
</Parent>
<Parent>
<Boy>Jay</Boy>
</Parent>
</Root>");
var q1 = from e in xml.XPathSelectElements("/Parent")
select e;
q1.Dump();
var q2 = from e in q1
let boy = ((IEnumerable<Object>)e.XPathEvaluate("Boy/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
let girl = ((IEnumerable<Object>)e.XPathEvaluate("Girl/text()")).Cast<System.Xml.Linq.XText>().FirstOrDefault() ?? new System.Xml.Linq.XText("")
select new {t=boy.GetType(), b=boy, g=girl, same=(boy.Value==girl.Value)};
q2.Dump();
}
结果是:
您可以看到第二个元素被标识为具有同名的男孩和女孩。在仍然使用 XPath 的同时是否有更简洁的方法,或者我是否坚持使用上面的代码。