2012-04-05 47 views
2

我最近發現一種情況,我必須將XPath用作Linq to XML查詢的一部分,並發現它有點奇怪。我確信還有其他解決使用本機XElement API方法的問題的方法,但在這種情況下,XPath更適合查找我需要的特定XML文本值,因爲文檔結構非常複雜。我最終找到了一種使其工作的方式(見下文),但它不是很漂亮,通常意味着我錯過了一些東西。使用XPathEvaluate在Linq-to-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(); 
} 

結果是:

enter image description here

你可以看到第二個元素標識爲具有相同名稱的男孩和女孩。在使用XPath的時候還有更乾淨的方法嗎?或者我堅持使用上面的代碼。

+0

您可以簡化您的XPath來獲取所有與你正在尋找標準的家長://父[男/文()=女孩/文()] – JWiley 2012-04-05 18:00:16

回答

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) }; 
+0

這是比我的好:(而且這所有下來到演員陣容(字符串) – Phil 2012-04-05 18:05:37

+2

'XElement'演員操作非常方便 – 2012-04-05 18:12:13

+0

非常好!我嘗試過,但我需要的文本節點不是完整的元素。看起來像我需要的只是投射到一個字符串。謝謝! – 2012-04-05 23:25:50

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