最近在用到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 }
运行结果
参考: