[C#] XmlDocument 搭配 Linq 與 XPath
2010-05-18 17:13
363 查看
一般最常搭配 XML 用來查詢資料的技術是 XPath 。不過 .Net 僅支援到 XPath 1.0 ,有時想在 XPath 中加上日期函式的判斷都不行。
再加上若使用了 XPath 的函式或一些判斷式後,整個 XmlDocument 的查詢效能會變慢。(參考以下的例子)
本文章所使用的 XML 內容 (ad.xml :紀錄一些廣告圖與連結):
view source
print?
假如我們現在要找出所有 <weight>值為 9 的 <item>,傳統上可用以下兩個方式:
(程式部分用迴圈跑 10000 次,來區分兩種做法的效能)
使用 XPath 做篩選:
view source
print?
在程式中判斷:
view source
print?
兩種做法的不同點只有在 SelectNodes 的地方,前者直接透過 XPath 篩選掉不符條件的節點;後者是將 <item>全取出後,在程式中判斷。
儘管效能上有差異,還是可以視情況選擇 XPath 使用的方式。例如僅單純地使用樹狀結構查詢所需的節點,並避免在 XPath 中使用一些函式去做文字或屬性值的判斷。
自從 .Net 出了 Linq 後,個人感覺對 XML 的查詢更有幫助了。(效能部分因為是端看怎麼查詢,較為主觀,這邊就不比較效能)
以上述的例子來看,我們可以用 Linq 的語法進行查詢: (僅供參考:效能大約介於上述兩個做法,300毫秒上下)
view source
print?
此用法的關鍵在於要將 SelectNodes 做一次 Cast ,轉為 XmlNode 。
接下來用一個例子來說明 XmlDocument + Linq 的好處。
假設本文所使用的 ad.xml 檔案是一個網站用來呈現廣告的資料來源,在前台會顯示的廣告圖共有三個,其中權重 (<weight>)為10的是一定要呈現的廣告,若權重相同,則以亂數決定。
基於少述的條件,可以大概知道查詢上除了權重 (<weight>)外,還要加上一個隨機的查詢條件,以造成圖片有隨時更換的效果。
如果用過去的查詢方式,大概會是如下的步驟:
先查出權重最高的並以亂數排序:將權重為10的 <item>再搭配上一個亂數進行排序,然後將前三名取出。
如果權重為10的項目未超過三個,需再從權重小於10的項目中再選出,選的過程還是要加入隨機值做排序。
一直重覆第2步,直到滿足廣告所需出現的數量 (ex: 三個)。
感覺上用資料庫的 SQL 句就可以很容易達成的事 (ORDER BY weight DESC, NEWID()DESC),到了 XML 就因為多了一個隨機亂數,而變得複雜。
現在,換用 Linq 做,程式碼大致如下:
view source
print?
上述的程式碼除了將 XML 中排序與亂數的問題解決,甚至利用 Take()就將最多只抓取三個廣告項這個條件也做掉了。
由於在 Linq中可以用到 .Net Framework的函式庫,所以像是日期或字串的判斷,也就顯得更為彈性。
以上供參考,例子舉得不好請見諒。
PS. 上述的例子,將第7行後的程式以迴圈方式連續執行10000次,大約花200毫秒,效能上並不會因為用了 Linq 而不好。
再加上若使用了 XPath 的函式或一些判斷式後,整個 XmlDocument 的查詢效能會變慢。(參考以下的例子)
本文章所使用的 XML 內容 (ad.xml :紀錄一些廣告圖與連結):
view source
print?
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < ads > |
03 | < item > |
04 | < title >我的E政府</ title > |
05 | < weight >10</ weight > |
06 | < image >http://www.gov.tw/images/head_logo.jpg%3C/ image > |
07 | < url >http://www.gov.tw/%3C/ url > |
08 | </ item > |
09 | < item > |
10 | < title >PChome Online 網路家庭</ title > |
11 | < weight >9</ weight > |
12 | < image >http://www.pchome.com.tw/img/pchomelogo.gif%3C/ image > |
13 | < url >http://www.pchome.com.tw/%3C/ url > |
14 | </ item > |
15 | < item > |
16 | < title >Yahoo!奇摩</ title > |
17 | < weight >9</ weight > |
18 | < image >http://l.yimg.com/f/i/tw/hp/mh/09purple.gif%3C/ image > |
19 | < url >http://tw.yahoo.com/%3C/ url > |
20 | </ item > |
21 | < item > |
22 | < title >巴哈姆特電玩資訊站</ title > |
23 | < weight >9</ weight > |
24 | < image >http://pic.bahamut.com.tw/index_w/baha_logo.jpg%3C/ image > |
25 | < url >http://www.gamer.com.tw/%3C/ url > |
26 | </ item > |
27 | </ ads > |
(程式部分用迴圈跑 10000 次,來區分兩種做法的效能)
使用 XPath 做篩選:
view source
print?
01 | XmlDocument doc = new XmlDocument(); |
02 | doc.Load( "ad.xml" ); |
03 | DateTime dtStart = DateTime.Now; |
04 | for ( int i = 0; i < 10000; i++) |
05 | { |
06 | XmlNodeList nodes = doc.SelectNodes( "//item[weight='9']" ); |
07 | foreach (XmlNode node in nodes) |
08 | { |
09 | string s = node.OuterXml; |
10 | } |
11 | } |
12 | Console.WriteLine(( "{0}(毫秒)" + DateTime.Now - dtStart).Milliseconds); |
13 | //輸出了: 337 (毫秒) |
view source
print?
01 | XmlDocument doc = new XmlDocument(); |
02 | doc.Load( "ad.xml" ); |
03 | DateTime dtStart = DateTime.Now; |
04 | for ( int i = 0; i < 10000; i++) |
05 | { |
06 | XmlNodeList nodes = doc.SelectNodes( "//item" ); |
07 | foreach (XmlNode node in nodes) |
08 | { |
09 | if (node[ "weight" ].InnerText == "9" ) |
10 | { |
11 | string s = node.OuterXml; |
12 | } |
13 | } |
14 | } |
15 | Console.WriteLine(( "{0}(毫秒)" + DateTime.Now - dtStart).Milliseconds); |
16 | //輸出了: 250 (毫秒) |
儘管效能上有差異,還是可以視情況選擇 XPath 使用的方式。例如僅單純地使用樹狀結構查詢所需的節點,並避免在 XPath 中使用一些函式去做文字或屬性值的判斷。
自從 .Net 出了 Linq 後,個人感覺對 XML 的查詢更有幫助了。(效能部分因為是端看怎麼查詢,較為主觀,這邊就不比較效能)
以上述的例子來看,我們可以用 Linq 的語法進行查詢: (僅供參考:效能大約介於上述兩個做法,300毫秒上下)
view source
print?
1 | XmlDocument doc = new XmlDocument(); |
2 | doc.Load( "ad.xml" ); |
3 | var query = from n in doc.SelectNodes( "//item" ).Cast<XmlNode>() |
4 | where int .Parse(n[ "weight" ].InnerText)== 9 |
5 | select n; |
6 | foreach (XmlNode node in query) |
7 | { |
8 | string s = node.OuterXml; |
9 | } |
接下來用一個例子來說明 XmlDocument + Linq 的好處。
假設本文所使用的 ad.xml 檔案是一個網站用來呈現廣告的資料來源,在前台會顯示的廣告圖共有三個,其中權重 (<weight>)為10的是一定要呈現的廣告,若權重相同,則以亂數決定。
基於少述的條件,可以大概知道查詢上除了權重 (<weight>)外,還要加上一個隨機的查詢條件,以造成圖片有隨時更換的效果。
如果用過去的查詢方式,大概會是如下的步驟:
先查出權重最高的並以亂數排序:將權重為10的 <item>再搭配上一個亂數進行排序,然後將前三名取出。
如果權重為10的項目未超過三個,需再從權重小於10的項目中再選出,選的過程還是要加入隨機值做排序。
一直重覆第2步,直到滿足廣告所需出現的數量 (ex: 三個)。
感覺上用資料庫的 SQL 句就可以很容易達成的事 (ORDER BY weight DESC, NEWID()DESC),到了 XML 就因為多了一個隨機亂數,而變得複雜。
現在,換用 Linq 做,程式碼大致如下:
view source
print?
01 | //廣告最多3則 |
02 | int intAdCount = 3; |
03 | //產生亂數的物件 |
04 | Random rnd = new System.Random(( int )DateTime.Now.Ticks); |
05 | XmlDocument doc = new XmlDocument(); |
06 | doc.Load( "ad.xml" ); |
07 | var query = (from n in doc.DocumentElement.SelectNodes( ".//item" ).Cast<XmlNode>() |
08 | orderby Convert.ToInt32(n[ "weight" ].InnerText)descending, rnd.Next(0, 10)descending |
09 | select n).Take(intAdCount); |
10 | foreach (XmlNode node in query) |
11 | { |
12 | string strTitle = node[ "title" ].InnerText; |
13 | string strImage = node[ "image" ].InnerText; |
14 | string strUrl = node[ "url" ].InnerText; |
15 | } |
由於在 Linq中可以用到 .Net Framework的函式庫,所以像是日期或字串的判斷,也就顯得更為彈性。
以上供參考,例子舉得不好請見諒。
PS. 上述的例子,將第7行後的程式以迴圈方式連續執行10000次,大約花200毫秒,效能上並不會因為用了 Linq 而不好。
相关文章推荐
- C#操作Xml的两种方式 XPath XmlDocument XmlNodeList
- C#操作Xml的两种方式 XPath XmlDocument XmlNodeList
- C# 关于 xmlreader xmldocument 和xpath 之间的性能比较
- c#操作xml文件(XmlDocument,XmlTextReader,Linq To Xml)
- C#操作Xml的两种方式 XPath XmlDocument XmlNodeList
- 使用 System.Xml.XmlDocument 类可在 Visual C#.net 中执行 XPath 查询
- C#操作Xml的两种方式 XPath XmlDocument XmlNodeList
- C#操作Xml的两种方式 XPath XmlDocument XmlNodeList
- XML 搜索和验证(XmlDocument、XPath to XmlDocument、LINQ to XDocument)
- C# Xml Linq XDocument 基本操作 -- 重新学习
- c#中使用linq to xml 访问 xml文件
- LINQ To XML:按文档定义的元素顺序显示元素InDocumentOrder
- C#程序中使用LINQ to XML来查询XML格式数据的实例
- C#操作xml之xpath语法
- c# xml XPath SelectNodes, SelectSingleNode 无法获取
- C#操作xml之xpath语法
- C#中的Linq to Xml详解
- XmlDocument与XPath(System.xml)
- C#操作xml SelectNodes,SelectSingleNode xmlns 总是返回NULL 与 xPath 介绍
- C#新手入门代码 LINQ TO XML xattribute的用法示例