最近在用到HtmlAgliltyPack進行結點查詢時,發現這里選擇結點使用的是XPath。所以這里總結一下在C#中使用XPath查詢XML的方法。習慣了用Linq,這里也是用的Linq to xml的。
Linq To XML的核心類是XDocument和XElement、XAttribute,需要引用using System.Xml.Linq命名空間。
這三個類簡單理解為:
XDocument:打開的整個XML文檔
XElement:節點元素
XAttribute:屬性
下面簡單介紹一下使用。
如有以下XML文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <html> 3 <head> 4 <title>測試XML</title> 5 </head> 6 <body> 7 <div class="card-container"> 8 <div class="item-title"> 9 <h3 class="item-shop-name">汪家羊肉館</h3> 10 </div> 11 <div class="item-comment"> 12 <span class="price1">¥62/人</span> 13 <span class="price2">¥12/人</span> 14 <span class="price3">2</span> 15 <span class="price4">12</span> 16 </div> 17 </div> 18 </body> 19 </html>
打開XML文件
1 XDocument doc = XDocument.Load("demo.xml");
獲取根節點(html節點 返回XElement類型)
var root = doc.Root;
獲取第一個子節點(返回XElement類型)
1 var firstNode = root.FirstNode;
獲取全部子節點(返回IEnumerable<XNode>)
1 var allChildNode = root.Nodes();
獲取指定名稱的第一個子節點(返回XElement類型)
1 var headNode = root.Element("head");
獲取指定名稱的全部子節點(返回IEnumerable<XElement>)
var allNamedNode = root.Elements("head");
獲取節點指定名稱的屬性(<div class="card-container"> )
1 var attribute = root.Element("body").Element("div").Attribute("class");
獲取節點的全部屬性
1 var allAttributes = root.Attributes();
使用XPath查詢(需要引用using System.Xml.XPath命名空間)
1 var xpathQeury = root.XPathSelectElement("body/div");
獲取節點的名稱和值
1 //獲取結點的名稱 2 var nodeName = root.Name; 3 //獲取節點的值 4 var nodeValue = root.Value;
保存XML
1 doc.Save("demo.xml");
Linq查詢(獲取<span class="price2">¥12/人</span>節點下的值)
這里僅做示例,返回返回IEnumerable<XElement>類型的都可以進行Linq查詢
不使用XPath
1 var queryResult = root.Element("body").Element("div").Elements("div").ElementAt(1).Elements("span").Where(x=>x.Attribute("class") != null && x.Attribute("class").Value == "price2").FirstOrDefault(); 2 if(queryResult != null) 3 Console.WriteLine(queryResult.Value);
使用XPath
1 var xpathQueryResult = root.XPathSelectElements("body/div/div[2]/span").Where(x => x.Attribute("class") != null && x.Attribute("class").Value == "price2").FirstOrDefault(); 2 if(xpathQueryResult != null) 3 Console.WriteLine(xpathQueryResult.Value);
輸出結果都為下
下面開始介紹XPath
XPath 是 XML 文檔中查找信息的語言,使用XPath可以對XML的元素進行查找。
這里重着介紹一下XPath語法
/ 從根節點開始選擇
1 var xpathRoot = doc.XPathSelectElement("/html"); 2 var xpathRoot2 = doc.XPathSelectElement("html");
運行結果
// 獲取文檔中所有指定的結點,不管它的位置
如要獲取xml文檔中所有的span節點
1 //以下獲取的結果都是一樣的 2 //盡管位置不一樣,但查詢結果是一樣的 3 var body = root.Element("body").Element("div").Elements("div").ElementAt(1); 4 var allDivNodeInBody = body.XPathSelectElements("//div"); 5 var allDivNodeInDoc = doc.XPathSelectElements("//div"); 6 Console.WriteLine(allDivNodeInBody.Count()); 7 Console.WriteLine(allDivNodeInDoc.Count());
運行結果
. 當前節點
1 var currentNode = root.XPathSelectElement("."); 2
運行結果
.. 當前節點的父節點
1 var parentNode = root.Element("body").XPathSelectElement("..");
運行結果
@ 選取屬性
這個操作在Linq to xml里不支持,會產生一個"XPath 表達式的計算結果為意外類型 System.Xml.Linq.XAttribute。"異常
通配查詢
* 全部節點
@* 全部屬性(不支持)
謂詞查詢
選擇第一個查詢結果,如<span class="price1">¥62/人</span>
//span[1]
1 var firstSpanNode = doc.XPathSelectElement("//span[1]");
運行結果
選擇最后一個查詢結果,如最后一個<span class="price4">12</span>
//span[last()]
1 var lastDivNode = doc.XPathSelectElement("//span[last()]"); 2 Console.WriteLine(lastDivNode.Attribute("class").Value);
運行結果
選擇帶有屬性class的div節點
//div[@class]
1 var nodeWithClassAttribute = doc.XPathSelectElements("//div[@class]"); 2 foreach (var item in nodeWithClassAttribute) 3 { 4 Console.WriteLine("===================="); 5 Console.WriteLine(item); 6 }
運行結果
選擇帶有屬性class,且值為item-title的div節點
//div[@class='item-title']
1 var nodeWithClassValueAttribute = doc.XPathSelectElements("//div[@class='item-title']"); 2 foreach (var item in nodeWithClassValueAttribute) 3 { 4 Console.WriteLine(item); 5 }
運行結果
簡單的選擇計算
獲取倒數第二個div節點
//div[last()-1]
1 var nextToLastDivNode = doc.XPathSelectElement("//div[last()-1]");
運行結果
獲取值大於10的span節點
//span[text()>10]
1 var greaterThanTenSpan = doc.XPathSelectElements("//span[text()>10]");
運行結果:
獲取值加10等於22的span節點
//span[text()+10=22]
1 var plusTenSpan = doc.XPathSelectElements("//span[text()+10=22]");
運行結果:
常用運行符如下
+ 加
- 減
* 乘
div 除
= 等於
!= 不等於
> 大於
< 小於
>= 大於等於
<= 小於等於
or 或
and 與
組合查詢
如查詢值等於12或等於2的span節點
//span[text()=2]|//span[text()=12]
1 var combineQuery = doc.XPathSelectElements("//span[text()=2]|//span[text()=12]"); 2 foreach (var item in combineQuery) 3 { 4 Console.WriteLine(item.Value); 5 }
運行結果
參考: