簡介
XPath是一種在一個XML文檔中尋址的語言,為XSLT和XPointer而設計。Path的主要目的是在一個XML文檔中尋址。支持這個主要目的,它還提供基本功能來操縱字符串、數字和布爾值。
在XPath 1.0和XSLT 1.0中,通常使用節點樹。 解析的XML文檔是一棵包含文檔節點及其后代的樹。 使用該節點樹,您可以找到根元素的節點,以及所有根元素的后代,屬性和同級。 (XML文件的根元素之外的任何注釋或處理指令都被視為根元素的同級。)
XPath 2.0和XSLT 2.0中的主要新概念之一是,一切都是序列。.net 6.0xpath 是xpath 2.0
XQuery1.0與XPath2.0有共同的數據模型即使:7個節點(即處理指令,元素,文檔節點,屬性,命名空間,文本節點和注釋。),所有的值都成為序列,序列由節點或原子值組成,如整數,字符串或布爾值。
Xpath 數據模型
XPath1.0與XPath2.0的區別
XPath2.0任何東西都是序列:這是因為XPath 2.0所有的表達式都返回序列。 節點集是有序的,
XPath2.0序列和包含重復的節點
XPath2.0完全支持 XML Schema 數據類型
XPath2.0序列很淺:序列之間不會發生嵌套,如果你試圖在序列中嵌套序列,當然在句法上可以接受,不過你得到的是一個“膨脹的”序列,子序列和包含它的序列仍然是依次排列的。
XPath2.0序列是有序的:XPath 2.0清楚的理解和表示序列中的次序,可以保持或者創造任何你指明的順序作為結果。在XPath 2.0中,序列取代了1.0中所謂的節點集(node-sets)。
XPath2.0Xpath加入了一些重要的關鍵字包括序列操作符,比如for、條件表達式、定量修飾符(quantifiers)和集合操作(集合的交、差和並)。同樣還有一個except操作符,它允許一項操作應用於一個序列中除了特定的成員之外的其他所有成員。你也會發現很多類型映射和強制轉換(coercion)的關鍵字。
C# 相對應的xpath命名空間
System.Xml.XPath概覽
該命名空間有兩個重要的類型:XPathDocument、XPathNavigator
XPathNavigator實現了DOM2級 種 遍歷和范圍模塊
XPath
重點:在應用xpath時候,要注意DOM標准 對節點的定義
DOM 是這樣規定的:
- 整個文檔是一個文檔節點
- 每個 XML 標簽是一個元素節點
- 包含在 XML 元素中的文本是文本節點
- 每一個 XML 屬性是一個屬性節點
- 注釋屬於注釋節點
XPath 的意思是 XML 路徑語言。它使用的一個非 XML 語法提供一種靈活地定位 XML (en-US) 文檔的不同部分的方法。它同時也可以用於檢測文檔中某個節點是否與某個模式(pattern)匹配。
XPath 主要被用於 XSLT,也可用於定位文檔元素,像類 XML 語言文檔(如HTML 和 XUL ) 通過 DOM (en-US) 定位元素一樣。替代 document.getElementById
方法、 element.childNodes
屬性和其他DOM核心特性。
XPath 使用路徑標識符通過層級結構來導航XML文檔。它使用非XML語法,以致於它可以被用在URIs和XML屬性值上。
【C# XPath】
xml常用的元素定位方式:css選擇器、 xpath
Xpath表達式
XPath工具
vs2022 XPath Tools
1、vs2022 擴展》管理擴展》下載 XPath Tools> 重啟 vs2022
2、光標定位 到元素的開始標簽,鼠標右鍵復制 xpath
3、可以鼠標右鍵 調出xpath tools 。自行寫xpath 測試
vscode xpath工具:xml tools
vscode Xpath工具:XSLT/XPath
1、vscode xpath下載插件xml tools
2、光標放在要定位的 開始元素標簽上,這邊用博客園的 "備份.xml"做測試
3、shift +ctrl+p >選擇 get current xpath
4、結果:/rss/channel/item[90]
瀏覽器 自帶的支持Xpath
路徑定位方式
絕對路徑:/setp/setp
相對路徑:setp/setp
案例:/root/parent/my/child/son
step:軸名稱::節點測試[謂語]
軸(axis相當於家族):定義所選節點與當前節點之間的樹關系
節點測試(node-test):識別某個軸內部的節點
零個或者更多謂語(predicate):更深入地提煉所選的節點集
/:表示根目錄 例如 # res=html.xpath('/html/body/*') # 找html下body下的所有標簽(只找子,不找孫)
//:當前位置 例如# res=html.xpath('/html/body//*') # 找html下body下的所有標簽(子子孫孫)
Xpath的基本使用方法
這部分內容來源:https://blog.csdn.net/ZYX_jber/article/details/120986932
實例 '//div[@id="example1"/input[@class="color:red"]'
斜線”/”是從根節點選擇,雙斜線”//”從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置,點”.”選取當前節點,兩點”..”選取當前節點的父節點,“@”為選取屬性。
1、斜線/從根節點選擇,基本的XPath語法類似於在一個文件系統中定位文件,如果路徑以斜線 / 開始, 那么該路徑就表示到一個元素的絕對路徑,獲取滿足該路徑的所有節點:
選擇根元素 語法:/AAA
選擇AAA的所有CCC子元素 語法:/AAA/CCC
2、如果路徑以雙斜線 // 開頭, 則表示選擇文檔中所有滿足雙斜線//之后規則的元素(無論層級關系),//會做全文檔掃描。
選擇所有BBB元素 語法://BBB
選擇所有父元素是DDD的BBB元素 語法://DDD/BBB
選擇AAA的CCC的所有BBB元素 語法:/AAA/CCC//BBB
3、點“.” 選取當前節點。
4、“..”選取當前節點的父節點。
5、”@”選取屬性。
選擇所有的id屬性 語法://@id 注意:這里選取的是屬性而不是方法。
選擇有id屬性的BBB元素 語法://BBB[@id] 區別於上面的屬性選擇
選擇id屬性為“b1”的BBB元素 語法://BBB[@id="b1"]
選擇有任意屬性的BBB元素 語法://BBB[@*]
選擇不具有任何屬性的BBB元素 語法://BBB[not(@*)]
謂語在XPath是重要的一部分,謂語用來查找某個特定的節點或者包含某個指定的值的節點。謂語被嵌在方括號中。[謂語]
1、選擇AAA下的第一個BBB元素 語法:/AAA/BBB[1]
2、選擇AAA下的最后一個BBB元素 語法:/AAA/BBB[last()]
3、選擇AAA下的倒數第二個BBB元素 語法:/AAA/BBB[last()-1]
4、選擇AAA下的前面兩個BBB元素 語法:/AAA/BBB[position()<3]
5、獲取AAA下的BBB下的有s屬性的CCC元素 語法:/AAA/BBB/CCC[@s]
6、選取所有 bookstore 元素的 book 元素,且其中的 price 元素的值須大於 35.00。 語法:/bookstore/book[price>35.00]
7、選取所有 bookstore 元素中的 book 元素的 title 元素,且其中的 price 元素的值須大於 35.00. 語法:/bookstore/book[price>35.00]/title
選擇未知的XML元素和選擇若干路徑。 *
1、星號 * 表示選擇所有由星號之前的路徑所定位的元素,*是通配符,表示該路徑下的所有元素,也表示層次。
選擇所有路徑依附於/AAA/CCC/DDD的元素 語法:/AAA/CCC/DDD/*
選擇所有的有3個祖先元素的BBB元素,即在第四層的BBB元素 語法:/*/*/*/BBB
選擇所有元素 語法://*
2、“@*”匹配任何屬性的節點,not(@*)匹配沒有任何屬性的節點。
3、“|”是多個路徑選擇的並集,可以利用“|”查找符合多個條件的節點。
獲取所有的BBB元素和EEE元素 語法://BBB|//EEE
獲取AAA下XXX下的DDD的BBB元素和EEE元素 語法:/AAA/XXX/DDD/BBB|/AAA/XXX/DDD/EEE
XPath 軸(axis::)定位方式(類比族譜)
【. 】: 當前當前節點的 子節點
【..】:當前當前節點的 父節點
【@】:屬性
【::】:軸格式 例如:軸(axis)::元素或者通配符*
Xpath軸關鍵字 | 軸的定義說明 | 定位表達式實例 | 表達式解釋 |
parent | 父母 | //img[@alt='div2-img2']/parent::div | 查找到alt屬性為div2-img2的img元素,並基於圖片找到其上一級的div元素 |
child | 子代 | //div[@id='div1']/child::img | 查找id為div1的div標簽,基於當前div查找標簽為img的子節點 |
ancestor | 祖代,父親和父親的父親,以此類推 | //img[@alt='div2-img2']/ancestor::div | 查找alt屬性為div2-img2的圖片,基於當前圖片找到其上級的div頁面元素 |
descendant | 后代,兒子和他們孩子以此類推 | //div[@id='div2']/descendant::img | 查找id屬性為div2的div元素,在查找其下級所有節點中的img元素 |
following | 弟弟妹妹和他們的孩子 | //div[@id='div1']/following::img | 查找到ID屬性為div1的div元素,並基於div的位置找到它后面節點中的img元素 |
following-sibling | 弟弟妹妹 | //img[@alt='div1-img1']/following-sibling::input | 查找到alt屬性為div1-img1的img頁面元素,並基於img的位置找到后續節點中的input元素 |
preceding | 哥哥姐姐和他們的孩子 | //img[@alt='div2-img2']/preceding::div | 查找到alt屬性為div2-img2的圖片頁面元素,並基於圖片的位置找到它前面節點中的div元素 |
preceding-sibling | 哥哥姐姐 | //img[@alt='div2-img2']/preceding-sibling::a[1] | 查找到alt屬性值為div2-img2的圖片元素,基於圖片位置找到它前面同級節點的第二個鏈接頁面元素 |
軸(類比族譜樹結構)Xpath的基本使用方法
XPath軸(XPath Axes)可定義某個相對於當前節點的節點集:
1、child 選取當前節點的所有子元素
child是Xpath默認的軸,可以省略不寫。下面看些簡單例子:
/child::AAA 等價於/AAA
2、parent 選取當前節點的父節點
parent軸是選取當前節點父節點,下面看簡單示例:
//DDD/parent::* 獲取所有節點DDD的父節點
/AAA/BBB/parent::* 得到根節點AAA,這樣寫在實際中沒有意義。
/AAA/parent::* 根節點無法獲取到parent
3、descendant 選取當前節點的所有后代元素(子、孫等)
descendant選取當前節點的所有后代元素(包括子節點、子孫節點…),descendant (后代)軸包含上下文節點的后代,一個后代是指子節點或者子節點的子節點等等。
/descendant::* 選擇文檔根元素的所有后代.即所有的元素被選擇
/AAA/BBB/descendant::* 選擇/AAA/BBB的所有后代元素
//CCC/descendant::* 選擇所有CCC元素的所有后代元素
//CCC/descendant::DDD 擇所有以CCC為祖先元素的DDD元素
4、ancestor 選取當前節點的所有先輩(父、祖父等)
ancestor軸(axis)包含上下節點的祖先節點, 該祖先節點由其上下文節點的父節點以及父節點的父節點等等諸如此類的節點構成,所以ancestor軸總是包含有根節點,除非上下文節點就是根節點本身.
/AAA/BBB/DDD/CCC/EEE/ancestor::* 選擇一個絕對路徑上的所有節點
//FFF/ancestor::* 選擇FFF元素的所有祖先節點
5、descendant-or-self 選取當前節點的所有后代元素(子、孫等)以及當前節點本身
descendant-or-self跟descendant類似,多了節點本身。
/AAA/BBB/descendant-or-self::* 選擇/AAA/BBB本身及所有后代元素
//CCC/descendant-or-self::* 選擇CCC的所有后代元素及本身
6、ancestor-or-self 選取當前節點的所有先輩(父、祖父等)以及當前節點本身
ancestor-or-self跟ancestor類似,多了本身節點,選取當前節點的所有先輩(父、祖父等)以及當前節點本身。
/AAA/BBB/DDD/CCC/EEE/ancestor-or-self::* 選擇/AAA/BBB/DDD/CCC/EEE的先輩及本身
//FFF/ancestor-or-self::* 選擇FFF元素的所有先輩以及FFF本身
7、preceding-sibling 選取當前節點之前的所有同級節點(前面的)
preceding-sibling,選取當前節點之前的所有同級節點,同一個parent下該節點之前的節點,即“哥哥”節點(是同父的哥哥節點)。
/AAA/XXX/preceding-sibling::* /AAA/XXX節點的所有之前同級節點
//CCC/preceding-sibling::* 選取所有CCC節點的同級哥哥節點
8、following-sibling 選取當前節點之后的所有同級節點(后面的)
following-sibling 選取當前節點之后的所有同級節點,跟preceding-sibling一樣都是選取同級同父的節點,只不過following是取對應節點之后的節點,preceding-sibling取的是該節點之前的節點。
/AAA/BBB/following-sibling::* 取/AAA/BBB節點的之后的所有同級節點
//CCC/following-sibling::* 選取所有CCC元素的之后所有同級節點
9、preceding 選取當前節點的開始標簽之前的所有節點
preceding選取文檔中當前節點的開始標簽之前的所有節點,包含同一文檔中按文檔順序位於上下文節點之前的所有節點,除了祖先節點。
/AAA/XXX/preceding::* 選取/AAA/XXX節點所有之前節點(除其祖先外)
//FFF/preceding::* 選取所有FFF節點的所有之前節點(除祖先外),在下面的例子中,選取的結果跟/AAA/XXX/DDD/FFF/preceding::*一樣
10、following 選取當前節點的結束標簽之后的所有節點
following選取文檔中當前節點的結束標簽之后的所有節點,包含同一文檔中按文檔順序位於上下文節點之前的所有節點,除了祖先節點。 following選取文檔中當前節點的結束標簽之后的所有節點跟preceding的范圍一樣,只是方向不同,following是向后選取,preceding是向前選取。
/AAA/BBB/following::* 選取/AAA/BBB節點后的所有節點
//ZZZ/following::* 選取所有ZZZ節點之后的節點
11、self 選取當前節點
self選取當前節點,單獨使用沒有什么意思,主要是跟其他軸一起使用,如ancestor-or-self,descendant-or-self.
12、attribute 選取當前節點的所有屬性
attribute軸選取當前節點的所有屬性,獲取的結果是屬性而不是節點,前面所有的軸都是選取節點。
/AAA/BBB/attribute::* 選取/AAA/BBB節點的所有屬性
//CCC/attribute::* 選取所有CCC節點的所有屬性
13、namespace 選取當前節點的所有命名空間節點
名稱空間軸用來選取名稱空間結點。每個元素結點都有一個專門名稱空間結點表示每個作用域名稱空間。
常用定位語句實例
-
//NODE[not(@class)] 所有節點名為node,且不包含class屬性的節點
-
//NODE[@class and @id] 所有節點名為node,且同時包含class屬性和id屬性的節點
-
//NODE[contains(text(),substring] 所有節點名為node,且其文本中包含substring的節點
//a[contains(text(),"下一頁")] 所有包含“下一頁”字符串的超鏈接節點
//a[contains(@title,"文章標題")] 所有其title屬性中包含“文章標題”字符串的超鏈接節點
-
//NODE[@id="myid"]/text() 節點名為node,且屬性id為myid的節點的所有直接text子節點
-
BOOK[author/degree] 所有包含author節點同時該author節點至少含有一個的degree孩子節點的book節點
-
AUTHOR[.="Matthew Bob"] 所有值為“Matthew Bob”的author節點
-
//*[count(BBB)=2] 所有包含兩個BBB孩子節點的節點
-
//[count()=2] 所有包含兩個孩子節點的節點
-
//*[name()='BBB'] 所有名字為BBB的節點,等同於//BBB
-
//*[starts-with(name(),'B')] 所有名字開頭為字母B的節點
-
//*[contains(name(),'C')] 所有名字中包含字母C的節點
-
//*[string-length(name()) = 3] 名字長度為3個字母的節點
-
//CCC | //BBB 所有CCC節點或BBB節點
-
/child::AAA 等價於/AAA
-
//CCC/descendant:😗 所有以CCC為其祖先的節點
-
//DDD/parent:😗 DDD節點的所有父節點
-
//BBB[position() mod 2 = 0] 偶數位置的BBB節點
-
AUTHOR[not(last-name = "Bob")] 所有不包含元素last-name的值為Bob的節點
-
P/text()[2] 當前上下文節點中的P節點的第二個文本節點
-
ancestor::BOOK[1] 離當前上下文節點最近的book祖先節點
-
//A[text()="next"] 錨文本內容等於next的A節點
練習案例
using System; using System.IO; using System.Xml; using System.Xml.XPath; public class Sample { public static void Main() { XmlDocument doc = new XmlDocument(); doc.Load("Books.xml"); XPathNavigator xPathNavigator=doc.CreateNavigator();//XmlDocument可以編輯 Console.WriteLine(xPathNavigator.CanEdit); XPathNavigator xPathNavigator2 = new XPathDocument("Books.xml").CreateNavigator();//XPathDocument不可以編輯 Console.WriteLine(xPathNavigator2.CanEdit); //定位到書列表 xPathNavigator.MoveToChild("bookstore", "http://www.contoso.com/books"); //添加一本書 using XmlWriter xmlWriter = xPathNavigator.AppendChild(); xmlWriter.WriteStartElement("book");//只能改變內存中文檔的結構,不能修改文件中文檔的結構,xmlWriter 不會影響xPathNavigator的位置 xmlWriter.WriteAttributeString("genre", "autobiography"); xmlWriter.WriteAttributeString("publicationdate", "2011-03-22"); xmlWriter.WriteElementString("title", "zhanzheng與和平"); xmlWriter.WriteStartElement("author"); xmlWriter.WriteElementString("first-name", "ai"); xmlWriter.WriteElementString("last-name", "len"); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.WriteStartElement("book");//只能改變內存中文檔的結構,不能修改文件中文檔的結構,xmlWriter 不會影響xPathNavigator的位置 xmlWriter.WriteAttributeString("genre", "autobiography"); xmlWriter.WriteAttributeString("publicationdate", "2011-03-22"); xmlWriter.WriteElementString("title", "jinrong"); xmlWriter.WriteStartElement("author"); xmlWriter.WriteElementString("first-name", "ai"); xmlWriter.WriteElementString("last-name", "len"); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); //AppendChildElement xPathNavigator.AppendChildElement(xPathNavigator.Prefix, "pages", xPathNavigator.LookupNamespace(xPathNavigator.Prefix), "100"); Console.WriteLine(xPathNavigator.OuterXml); //選擇書本 帶有命名空間 XmlNamespaceManager xmlNamespaceManager = new(xPathNavigator.NameTable);//命名空間管理 xmlNamespaceManager.AddNamespace("bk", "http://www.contoso.com/books");//添加命名空間 XPathExpression xPathExpression =XPathExpression.Compile("descendant::bk:book[bk:author/bk:last-name = 'len']");//新建表達子 xPathExpression.SetContext(xmlNamespaceManager);//將命名空間和表達式關聯 XPathNodeIterator items= xPathNavigator.Select(xPathExpression); do { //clone 一本書 XPathNavigator item = items.Current; Console.WriteLine("book title:{0}", item.Value); Console.WriteLine($" Count:{items.Count} Current:{items.Current} CurrentPosition:{items.CurrentPosition}"); //刪除 一本書 items.Current.DeleteSelf(); } while (items.MoveNext()); //刪除范圍之內的書 xPathNavigator.MoveToRoot(); XPathNavigator first = xPathNavigator.SelectSingleNode("descendant::bk:book[1]", xmlNamespaceManager); XPathNavigator last = xPathNavigator.SelectSingleNode("//bk:book[2]", xmlNamespaceManager); xPathNavigator.MoveTo(first); xPathNavigator.DeleteRange(last); Console.Clear(); Console.WriteLine(xPathNavigator.OuterXml); } }