2011/01/27

[XPath][C#] 利用 XPath 的 contains 查詢特定的元素

透過 .Net 處理 XML 時, 有時會想要類似 SQL 裡的 IN (‘a’, b’, 'c’) 的查詢方式.
查一下 w3schools 的 XPath 函式庫, 可以發現一個 function 還蠻符合的:
fn:index-of((item,item,...),searchitem)
只是一套用到程式中, 就會產生以下的 Exception:
Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
發生此問題的原因在於 .Net 並未完全支援 XPath 的函式, 有興趣的可以參考這個網址.
不過我發現有一個函式還不錯: fn:contains(string1,string2)
Returns true if string1 contains string2, otherwise it returns false
Example: contains('XML','XM')
Result: true
所以以下我用 w3schools 中的一個 CD catalog 的範例檔, 試著做出類似 index-of 的查詢方式, 來查出 <COUNTRY> 是 UK 或 EU 的 CD:
  • Linq: 利用字串陣列中的 Contains 進行比對
    string[] lstQuery = {"UK", "EU"};
    XmlDocument doc = new XmlDocument();
    doc.Load(@"test.xml");
    var query = from cd in doc.SelectNodes("//CD").Cast<XmlNode>()
          where lstQuery.Contains(cd["COUNTRY"].InnerText)
          select cd;
    foreach (XmlNode node in query)
    {
      Console.WriteLine(node.OuterXml);
    }
  • XPath:
    1. 將查詢條件的 UK 和 EU 組合成 '|UK|EU|', 其中 '|' 只是個分隔符號, 可以視查詢條件修改成一個不會有衝突的符號.
    2. 將 <COUNTRY> 中的文字組合為 '|UK|’ 的形式, 以方便後續進行 contains 的比對.
      (這邊要注意字串合併的部分要用 XPath 的 concat, 而不是寫成 '|COUNTRY|’)
    string[] lstQuery = {"UK", "EU"};
    XmlDocument doc = new XmlDocument();
    doc.Load(@"test.xml");
    XmlNodeList list = doc.SelectNodes(
      "//CD[contains('|"+string.Join("|",lstQuery)+"|',concat('|',COUNTRY,'|'))]");
    foreach (XmlNode node in list)
    {
      Console.WriteLine(node.OuterXml);
    }
雖然以上兩種方式都能達到一樣的效果, 但要說到字串處理, 還是在 .Net 裡處理會比較方便.
個人只是提供另一種資料處理方式而已. :)

沒有留言: