我最近遇到过一种情况,我必须使用XPath作为Linq to XML查询的一部分,并发现它有点奇怪。我确信还有其他方法可以使用本机XElement API方法解决问题,但在这种情况下,XPath更适合定位我需要的特定XML文本值,因为文档结构非常复杂。我最终找到了一种让它工作的方法(见下文),但它不是很漂亮,这通常意味着我错过了一些东西。
我的问题是如何使用XPathEvalute或其他一些XPath方法返回一个字符串值,该值可以在where语句中使用,也可以作为select方法中新对象的一部分使用。我找到了一个使用大量演员和Null coalesing operator in LINQ的解决方案,但必须采用更清洁的方式。问题的根源是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时是否有更干净的方法可以做到这一点,或者我使用上面的代码。
答案 0 :(得分:5)
使用XPathSelectElement
代替XPathEvaluate
是否可以接受?
var q2 = from e in q1
let boy = (string)e.XPathSelectElement("Boy")
let girl = (string)e.XPathSelectElement("Girl")
where boy.StartsWith("A") //Optional use in where statement
select new { t = boy.GetType(), b = boy, g = girl, same = (boy == girl) };
答案 1 :(得分:0)
这个怎么样,不确定你是否需要't'。
var q2 = q1.Select (q =>
new
{
Boy = q.XPathSelectElement("Boy"),
Girl = q.XPathSelectElement("Girl"),
}
);
var q3 = q2.Select (q =>
new
{
Boy = q.Boy == null ? string.Empty : q.Boy.Value,
Girl = q.Girl == null ? string.Empty : q.Girl.Value
}
);
var q4 = q3.Select (q => new { q.Boy, q.Girl, same=q.Boy==q.Girl });
q4.Dump();
可以改写为
var q2 = q1.
Select (q => new { Boy = q.XPathSelectElement("Boy"),Girl = q.XPathSelectElement("Girl"),}).
Select (q => new { Boy = q.Boy == null ? string.Empty : q.Boy.Value, Girl = q.Girl == null ? string.Empty : q.Girl.Value}).
Select (q => new { q.Boy, q.Girl, same=q.Boy==q.Girl }
);
q2.Dump();