日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

通过 .NET Framework 中的 XPath 和 XSLT API 方便地操作 XML 数据

發布時間:2023/12/20 asp.net 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通过 .NET Framework 中的 XPath 和 XSLT API 方便地操作 XML 数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文假設您熟悉 Visual Basic .NET

下載本文的代碼: XPathandXSLT.exe (166KB)

摘要

XPath 是一種正在興起的通用查詢語言。通過 XPath,可以在基于 XML 的數據源中識別和處理一組相關的節點。XPath 提供了一個基礎結構,它是 .NET Framework 中的 XML 支持的組成部分。XPath 導航模型甚至用在 XSLT 處理程序的內部。在本文中,作者考察了 XPath 導航器和 XSLT 處理程序的實現細節,并且包含了一些實際的示例,例如異步轉換、排序節點集和 ASP.NET 服務器端轉換。

XML 的主要優點之一是,它使您可以用標記和屬性標記文本的某些部分。您在文本內部標記數據的原因是您計劃以后檢索它。那么,如何完成這一工作呢?您可以使用 XPath。

雖 然 XPath 不具有基于 XML 的語法,但它是為了以簡潔的、相對簡單的方式對 XML 文檔的某些部分進行尋址而定義的語言。更為重要的是,XPath 定義了一種常見的語法,以便您可以從實現了 XML 文檔對象模型 (DOM) 的類內部以及從 XSLT 中檢索節點。

在 Microsoft?.NET Framework 中,通過在 System.Xml.XPath 命名空間中定義的類對 XPath 查詢語言提供了完整的支持。.NET Framework 對 XPath 的實現基于語言分析程序和評估引擎。XPath 查詢的整體體系結構與數據庫查詢類似。就像 SQL 命令一樣,需要準備 XPath 表達式并將它們提交給運行庫引擎以進行評估。查詢是針對 XML 數據源加以分析和執行的。接下來,您將取回一些表示查詢的結果集的信息。XPath 表達式可以返回節點集(即,有序的節點集合)、布爾值、數字或字符串。

在本文中,我將說明 XPath 如何與 .NET Framework 中的 XmlDocument 類和 XSLT 集成。我還將對 XPathNavigator 類(.NET Framework 使用它來遍歷 XML 文檔)進行深入的剖析。

XPath 表達式

XPath 是一種專門設計的查詢語言,用于對 XML 文檔的元素和文本進行尋址。XPath 表示法在本質上是聲明性的。任何有效的表達式都會使用強調節點之間層次關系的表示法來聲明節點模式。與文件系統路徑類似,XPath 表達式從根(XPath 術語中的軸)前進至源文檔中的特定節點集或值。然而,它與文件系統的相似性并不僅限于此。XPath 表達式總是在節點的上下文中求值。上下文節點由應用程序指定,并且代表查詢的起點。它與當前目錄的概念沒有太大區別。

XPath 查詢的上下文包括但不限于上下文節點和上下文節點集。上下文節點集是查詢所處理的節點的整個集合。通常,它是實際返回到應用程序的節點集的超集。 XPath 上下文還包含位置和命名空間信息、變量綁定和一個可供應用程序擴展的標準函數庫。XPath 分析程序的任何實現都提供了一個用于對表達式進行求值的函數庫。擴展函數被定義在特定于供應商的 XPath 實現中,但是也可以由專用的和基于 XPath 的編程 API(例如,XSL 轉換和 XPointer)提供。XPath 表達式通常會返回節點集,但是布爾值、字符串、數字和其他類型也受到支持。

最常用的 XPath 表達式類型是位置路徑。位置路徑是一個看起來與文件系統路徑非常類似的表達式,它既可以是絕對路徑,也可以是相對于上下文節點的相對路徑。絕對位置路徑以正斜杠開始。如圖 1 中所示,完全限定位置路徑由三部分組成:軸、節點測試以及一個或多個謂詞。軸信息定義表達式的初始上下文節點集,而節點測試是標識該節點集中路徑的一系列節點名稱。謂詞是一個邏輯表達式,它定義了用于篩選當前節點集的條件。

圖 1 位置路徑

XPath 表達式可以包含任何數量的謂詞。如果沒有指定任何謂詞,則在查詢中返回該上下文節點的所有子節點。否則,使用簡捷的 AND 運算符將用各種謂詞設置的條件邏輯地串聯在一起。請注意,謂詞按照它們出現的順序進行處理,以便下一個謂詞對上一個謂詞生成的節點集起作用。

在 進行處理時,XPath 表達式在名為位置步驟的子表達式中被標記化,并且每個表達式都分別被計算。XPath 處理程序以迭代方式傳遞在上一步中生成的子表達式和上下文節點集。它返回一個可能縮小的節點集,以便用作下一個子表達式的輸入參數。在該過程中,上下文節 點、位置和大小都可能變化,而變量和函數引用以及命名空間聲明保持不變。每個位置步驟實際上都是一個位置路徑,因此,可以根據需要以縮寫形式或完全限定形 式來表示。位置步驟由正斜杠分隔。

在 .NET Framework 中,可以通過 XmlNode 類在 XmlDocument 類中公開的方法或者通過 XPathNavigator 類使用 XPath 表達式。

XPath 導航器

在 .NET Framework 中,XmlDocument 類代表由 W3C 批準的標準 XML DOM(DOM 級別 2 標準)。在從 XmlDocument 中到達的每個子節點上,都實現了幾個搜索方法。XmlNode 類提供了 SelectNodes 和 SelectSingleNode 方法,它們使用 XPath 表達式在文檔中搜索節點。這些方法幾乎與基于 COM 的 MSXML 庫中具有類似名稱的方法完全相同。SelectNodes 返回一系列對象,而 SelectSingleNode 只返回第一個匹配搜索條件的對象。以下是使用 SelectNodes 的方法:

Dim doc As XmlDocument = New XmlDocument()
doc.Load(fileName)
Dim nodes As XmlNodeList
nodes = doc.SelectNodes(queryString)

SelectSingleNode 方法與 SelectNodes 的不同之處在于它返回單個 XmlNode 對象。稍后,我將詳細討論這些方法。

對 XPath 表達式的 XmlDocument 支持具有兩個目標。它使從 MSXML COM 代碼到 .NET Framework 的轉換變得順暢,同時提供了一種在內存映射 XML 文檔中搜索節點的內置機制。然而,XmlDocument 查詢 API 是簡單的高級別包裝。用于處理 XPath 表達式的核心 .NET Framework API 是圍繞 XPathNavigator 類生成的。導航器是一個 XPath 處理程序,它在任何公開 IXPathNavigable 接口的 XML 數據存儲區之上工作。導航器通過 XPathNavigator 類中定義的接口呈現,它使用 Select 方法分析和執行表達式。與 XmlDocument 方法不同,導航器接受以純文本形式提供的以及通過預編譯對象提供的表達式。可以從 XmlDocument 類或 XPathDocument 類中以編程方式訪問 XPathNavigator 對象。圖 2 說明了兩種訪問 .NET Framework 中的 XPath 函數的方式。

圖 2 訪問 XPath 函數

以下代碼片段顯示了如何根據 XML 文檔創建 XPathNavigator 以及如何執行 XPath 查詢:

Dim doc As XPathDocument
Dim nav As XPathNavigator
Dim iterator As XPathNodeIterator
doc = New XPathDocument(fileName)
nav = doc.CreateNavigator()
iterator = nav.Select(queryString)
While iterator.MoveNext()
' nav points to the node subtree
End While

導航器返回一個 XPath 迭代器對象。迭代器只是用來在返回的節點集中移動的專用枚舉器對象。稍后我將討論迭代器。

文檔、導航器和讀取器

在 .NET Framework 出現之前,處理 XML 文件涉及到處理按照 SAX 或 XmlDocument 規范呈現的文檔。

XPath 處理程序(它是分析和執行 XPath 查詢的引擎)是在 XPathNavigator 類的內部生成的。如圖 2 所示,XPath 計算總是被委托給導航器,而不管高級別調用方 API 是哪個。導航器在特定的數據存儲區(通常是 XPathDocument 類的實例)之上工作。只要數據存儲區類實現了如下所示的 IXPathNavigable 接口,則也可以使用其他數據存儲區:

public interface IXPathNavigable {
XPathNavigator CreateNavigator();
}

除了 XPathDocument 類以外,數據存儲區的示例還包括 XmlDocument 和 XmlDataDocument。

數 據存儲區負責提供導航器以探索內存中的 XML 內容。XPathNavigator 實現總是特定于存儲區,并且通過從 XPathNavigator 抽象類繼承生成。盡管實際上您總是通過 XPathNavigator 的常見引用類型來編寫導航器,但每個數據存儲區類都具有它自己的導航器對象。它們是內部的未記錄的類,無法以編程方式訪問,并且通常以相當不同的方式實 現。圖 3 列出了 .NET Framework 中定義的三個 XPath 數據存儲區所使用的真實導航器類。特定于文檔的導航器利用文檔類的內部布局以便提供導航 API。

XPathDocument 類為 XML 文檔提供高度優化的、只讀的內存中存儲區。該類是專門設計以實現 XPath 數據模型的,它沒有為節點提供任何標識。它只是創建一個基礎的節點引用樹,以便讓導航器能夠快速和有效地操作。XPathDocument 類的內部體系結構看起來像是節點引用鏈表。節點是通過一個代表 XmlNode 類的小型子集的內部類 (XPathNode) 來管理的(參見圖 2)。

與 XPathDocument 相比,XmlDocument 類提供了對基礎 XML 文檔的節點的讀寫訪問。此外,還可以分別訪問每個節點。

XmlDocument 類還提供了創建導航器對象的能力,如下所示:

Dim doc As XmlDocument = New XmlDocument()
doc.Load(fileName)
Dim nav As XPathNavigator = doc.CreateNavigator()

XmlDocument 的導航器類實現了 IHasXmlNode 接口。該接口定義了一個方法,即 GetNode:

public interface IHasXmlNode {
XmlNode GetNode();
}

使用該方法,調用方可以基于 XPathNavigator 的位置訪問和詢問 XmlDocument 中當前選擇的節點。無法為基于 XPathDocument 的導航器實現該功能,原因僅僅在于它不像 XmlDocument 類那樣通過 XmlNode 類公開內部結構。這是設計使然。XPathDocument 最大限度地減小了內存足跡,并且不提供節點標識。

因為 GetNode 方法是在 XmlDocument 上的 XPathNavigator 類上實現的,所以調用方可以通過類型轉換來利用它,如以下代碼片段所示:

Dim doc As XmlDocument = New XmlDocument()
doc.Load(fileName)
Dim nav As XPathNavigator = doc.CreateNavigator()
Dim i As XPathNodeIterator = nav.Select(query)
Dim node As XmlNode = CType(i.Current, IHasXmlNode).GetNode()

此時,調用方程序已經獲得了對該節點的完全訪問權限,并且可以任意讀取和更新它。

最 后,XmlDataDocument 類是 XmlDocument 的擴展,其目標是允許通過 XML 操作關系數據集。這是一個簡潔的示例,它說明了 .NET Framework 導航 API 可以應用于基于 XML 的數據以及類似于 XML(數據的結構類似于 XML,但不是 XML)的數據這樣一個事實。

如果您查看 XPath 導航器的 MSDN? 文檔,則將看到導航器以類似于游標的方式(向前和向后)從基于 XML 的數據存儲區中讀取數據,并且提供對基礎數據的只讀訪問。此外,它保持有關當前節點的信息,并且使用多種移動方法推進內部指針。當導航器定位于給定的節點 時,它的所有屬性都將反映該節點的值。當然,這類似于 XML 讀取器(我在 MSDN Magazine 的 2003 年 5 月刊的一篇文章中對它進行了討論。那么,導航器和讀取器之間有什么區別呢?

導 航器和讀取器是不同的東西。讀取器類似于水龍帶游標,它提供基本的只讀、只進移動。導航器也是只讀的,但是它們提供了一組豐富得多的移動方法(包括向前和 向后選項)。導航器還提供了多個選擇方法以對搜索進行微調。讀取器是更低級別的工具,可以用來讀取基于 XML 或類似于 XML 的數據,以及生成內存中的數據結構。XML 讀取器可以用來生成導航器所依賴的內存中數據結構。

查詢節點

假設您需要在基 于 .NET Framework 的應用程序中實現 XPath 查詢。是應當使用 XPath 導航器,還是最好堅持使用 XmlDocument 的節點接口呢?XmlNode 的 SelectNodes 方法在內部使用導航器對象來檢索匹配節點列表。隨后,使用導航器的 Select 方法的返回值以便初始化一個類型為 XPathNodeList(它定義在 System.Xml.XPath 命名空間中)的內部節點列表對象。正像您可能已經猜到的那樣,該類從已記錄的 XmlNodeList 類繼承。此外,與 SelectNodes 不同的是,導航器可以完全利用已編譯的表達式。

SelectNodes 方法總是以純文本形式接受 XPath 表達式。字符串隨后被逐字地傳遞給導航器。只有在一種情況下,基礎導航器才會收到已編譯的表達式。如果您使用處理命名空間信息的 SelectNodes 方法重載,則會首先編譯 XPath 表達式,然后將其傳遞給處理程序。重載方法的原型如下所示:

Function SelectNodes( _
xpathExpr As String, _
nsm As XmlNamespaceManager) _
As XmlNodeList

當您在會話中頻繁重用該表達式時,使用已編譯表達式的優點變得非常明顯,并且它們具有命名空間識別功能。XmlNamespaceManager 類允許用戶指定要綁定的命名空間的前綴。

SelectSingleNode 方法是 SelectNodes 的特例,它只返回所返回節點集中的第一個元素。遺憾的是,直到現在,SelectSingleNode 的實現也不是特別有效。如果您只需要找到第一個匹配節點,則調用 SelectSingleNode 或 SelectNodes 幾乎完全相同。而且,如果您需要盡一切可能提高性能,則使用 SelectNodes 可能更好。下面的偽代碼說明了 SelectSingleNode 的當前實現:

Function SelectSingleNode(xpathExpr As String) As XmlNode
Dim nodes As XmlNodeList = SelectNodes(xpathExpr)
Return nodes(0)
End Function

該方法在內部調用 SelectNodes,并且返回第一個匹配節點。但是,請注意,XmlNodeList 是動態生成的 — 只有在收到請求時,才會搜索下一個節點。

一種更好的查詢單個節點的方式是,向 SelectNodes 傳遞一個能夠返回單個節點的更為精確的 XPath 表達式。其思想是避免使用如下所示的一般性通配符表達式:

NorthwindEmployees/Employee

您應當在 XPath 表達式上放置一個更強的篩選器,以便它返回大小正確的節點子集。要只獲得第一個節點,請添加一個額外的謂詞,以便在找到第一個匹配項之后停止查詢:

NorthwindEmployees/Employee[position() = 1]

這通常是 XPath 最佳做法,并且并不特別歸因于 .NET Framework 實現。可以對該方法進行提煉和概括,以便根據需要調整節點集的大小。下面的查詢字符串顯示了如何獲得頭 n 個匹配的節點:

NorthwindEmployees/Employee[position() < n+1]

當您需要對采用某種形式的節點標識的選定節點執行操作時,我建議您使用 XmlNode 的 SelectNodes 而不是 XPathNavigator 的實例來執行 XPath 查詢。如果您需要將該節點作為 XmlNode 類的實例進行進一步的管理,則使用 SelectNodes 可以簡化代碼。

用 XPathNavigator 編程

讓我們再學習一點兒有關 XPathNavigator 的編程接口的知識。通常,不管使用哪個應用程序級別的 API,對 XML 數據源執行 XPath 查詢所需的步驟序列大致是相同的:

  • 獲得對支持 XPath 的文檔類的引用(例如,XPathDocument 或 XmlDocument 類的實例)。

  • 為指定的數據存儲區創建一個導航器對象。

  • 如果您計劃以后重用 XPath 表達式,則還可以對其進行預編譯。

  • 調用導航器的 Select 方法以采取操作。

  • 導 航器對象的編程接口定義在 XPathNavigator 抽象類中。盡管您通常使用導航器對象來執行 XPath 查詢,但讓 XPathNavigator 類代表更為通用的組件是不值得的。導航器是一個一般性的接口,它充當類似于游標的探測器,以探測任何將其內容作為 XML 公開的數據存儲區。盡管在功能上類似于 XML 讀取器,但對于簡單的讀取操作而言,導航器卻沒有前者快速和有效,這是因為它是一個樹導航器,并且專門用于進行檢索。如果您只需要讀取 XML 文檔,請使用 XML 讀取器;如果您需要執行查詢,請使用導航器。請記住,現在導航器在完全內存映射數據源上工作。

    從功能上 說,XPathNavigator 類與只是將導航文檔內容所需的所有方法組合在一起的偽類沒有太大不同。較大的差異在于,XPathNavigator 是一個與文檔類完全分離的獨特組件。換句話說,XPathNavigator 代表某種已經映射到 XML 數據模型的數據存儲區的 XML 視圖。

    圖 4 枚舉了 XPathNavigator 類上的可用屬性。像 XML 讀取器和 XMLDocument 類一樣,XPathNavigator 利用了名稱表來更有效地存儲重復字符串。該屬性集看起來像是表征 XmlTextReader 類中當前節點的屬性的子集。

    值得重復說明的是,XPathNavigator 的 Select 方法返回一個迭代器對象,該對象的當前元素被作為導航器(XPathNavigator 類)向后引用。要訪問和處理節點信息,您只能使用該導航器的屬性。圖 4 中的屬性是只讀的,并且更為重要的是,它們沒有映射到 XmlNode 類的實例。如果您需要將該節點作為 XmlNode 對象進行操作(例如,為了應用更改),以確保將 XmlDocument 用作數據存儲區類,然后將迭代器的當前元素轉換為 IHasXmlNode。從引用類型中,IHasXmlNode 調用 GetNode 方法,該方法返回基礎節點的 XmlNode 實例。在其他所有情況下,對節點的訪問權限是只讀的。

    導航器對象提供了一組豐富的方法,我基于這些方法的功能將它們劃分為三個主要的組:選擇、移動和雜項。以下代碼片段選擇節點的子孫。用于獲得祖先的代碼幾乎完全相同:

    Dim doc As XPathDocument = New XPathDocument(fileName)
    Dim nav As XPathNavigator = doc.CreateNavigator()
    nav.SelectDescendants(nodeName, nsUri, selfIncluded)

    SelectDescendants 采用該節點的本地名稱并選擇子孫。NsUri 變量指示子孫節點的命名空間 URI(如果存在的話)。SelfIncluded 布爾型變量是一個標志,它指示是否應該將該上下文節點包括在節點集中。

    圖 5 包含了 XPathNavigator 的移動方法的列表。您可以按照命名空間限制,向任一方向跳躍 — 向前或向后(從同輩到同輩)。您可能已經注意到,有三組不同的移動方法,它們分別適用于元素、屬性和命名空間節點。只有 MoveTo 和 MoveToRoot 方法可以在任何節點(不管類型如何)上調用。此外,屬性和命名空間還具有用于返回其值的方法:GetAttribute 和 GetNamespace。當被選擇時,導航器的 Name 屬性返回命名空間前綴。Value 屬性返回 URI。

    圖 6 對 XPathNavigator 類上定義的其他所有方法進行了分組。其中幾個方法與 XPath 表達式有關。XPath 表達式是一個代表位置路徑的字符串(盡管它不僅僅是普通的命令字符串)。它具有由 XPathExpression 類封裝的環繞上下文。表達式的上下文包括返回類型和命名空間信息。XPathExpression 類不是可公開創建的。要獲得它的新實例,必須取得一個 XPath 字符串表達式并將其編譯為 XPathExpression 對象。下面的代碼片段顯示了如何編譯表達式并顯示它的預期返回類型:

    Dim expr As XPathExpression = nav.Compile(xpathExpr)
    Console.WriteLine(expr.ReturnType.ToString())
    nav.Select(expr)

    已編譯的 XPath 表達式可以由 Select、Evaluate 和 Matches 方法使用。這里的術語“編譯”并不意味著 XPath 表達式成為可執行的表達式。更簡單地說來,必須將編譯操作視為通過收集各種信息片段產生對象的過程。表達式可以返回除節點集以外的各種類型的值。在這種情 況下,使用 Evaluate 方法計算該表達式,然后將返回的一般對象轉換為特定的類型。Select 是一個更為特殊的方法,因為它假定返回類型是節點集并且將這些節點插入到迭代器中。

    對節點集進行排序

    XPathExpression 類中內置的一個有趣的擴展是能夠在將節點集傳回調用方之前對其進行排序。要添加排序算法,需要調用 XPathExpression 對象上的 AddSort 方法。AddSort 具有兩種形式:

    Sub AddSort(expr As Object, comparer As IComparer)

    Sub AddSort(expr As Object, order As XmlSortOrder, _
    caseOrder As XmlCaseOrder, lang As String, _
    dataType As XmlDataType)

    Expr 參數表示排序關鍵字。它可以是表示節點名稱的字符串,也可以是另外一個能夠計算為節點名稱的 XPathExpression 對象。在第一個重載中,comparer 參數引用實現了 IComparer 接口的類的一個實例。該接口提供了 Compare 方法,該方法實際上用于比較一對值。如果您需要指定一個自定義算法以便對節點進行排序,則請使用該重載。

    第二個重載總 是根據 dataType 參數的值執行數值或文本比較。此外,您還可以指定排序順序(升序或降序),甚至指定大寫和小寫字母的排序順序(或者,您可以通過使用值 XmlCaseOrder.None 完全忽略大寫)。最后,lang 參數指定要使用哪種語言進行比較。語言名稱還應當指定區域設置。例如,要指示美國英語,最好使用“us-en”而不是簡單地使用“en”。

    讓 我們更深入地討論一下 IComparer 接口。為了對對象數組進行排序,.NET Framework 提供了幾個預定義的比較器類,包括 Comparer 和 CaseInsensitiveComparer。比較器類相對于大小寫比較對象(通常為字符串)。CaseInsensitiveComparer 完成相同的工作,但忽略大小寫。要在代碼中使用這兩個類,請確保導入 System.Collections 命名空間。Comparer 類不具有公共構造函數,但是通過 Default 靜態屬性提供了單個實例。例如:

    expr.AddSort("lastname", Comparer.Default);

    如果需要,您還可以創建自己的比較器類。以下代碼顯示了一個相當平常的 Visual Basic? .NET 實現:

    Class MyOwnStringComparer
    Implements IComparer
    Public Function Compare(x As Object, y As Object) _
    As Integer Implements IComparer.Compare
    Dim strX As String = CType(x, String)
    Dim strY As String = CType(y, String)
    Return String.Compare(strX, strY)
    End Sub
    End Class

    The Compare method should如果兩個字符串相等,則 Compare 方法應當返回 0;如果 x 先于 y,則該方法返回一個大于 0 的值;如果 y 先于 x,則它返回一個負值。

    該類還可以定義在應用程序的體中,并且不需要單獨的程序集。以下代碼將一個自定義比較器與一個 XPath 表達式相關聯:

    Dim comp As MyOwnStringComparer = New MyOwnStringComparer()
    expr.AddSort("lastname", comp)

    圖 7 顯示了該技術的一個應用。在為 XML 文檔創建導航器之后,示例控制臺應用程序編譯要使用的表達式。假設的數據源具有以下架構:

    <MyDataSet>
    <NorthwindEmployees>
    <Employee>
    <employeeid>...</employeeid>
    <lastname>...</lastname>
    <firstname>...</firstname>
    <title>...</title>
    </Employee>
    ???
    </NorthwindEmployees>
    </MyDataSet>

    按照單個節點進行排序是容易的 — 只須將節點名傳遞給 AddSort 方法。按照多個字段進行排序更為復雜。其思想是指示一個由逗號分隔的節點名稱列表。但是,參數字符串必須是一個能夠計算為由逗號分隔的節點名稱列表的 XPath 表達式。如果簡單地將排序關鍵字指定為類似于“title, lastname”的形式,則您將獲得運行庫錯誤,因為 XPath 處理程序錯誤地將其當作實際的節點名稱。真正需要的是 XPath 處理程序能夠在運行時將其轉換為所需頭銜和姓氏的表達式,如下所示:

    Dim sortKey As String = "concat(concat(title, ','), lastname)"

    Concat 關鍵字標識 XPath 實現提供的預定義 Helper 函數之一。

    在圖 7 中,您還可以了解如何有效地使用迭代器。在使用 XPath迭代器時需要注意的一個要點是,代碼一次遍歷節點集中的所有節點。

    您可能需要深入到其中每個節點的子樹中。為此,請首先克隆導航器以避免放錯主要的導航器,從而損害最外層的循環:

    Dim iterator As XPathNodeIterator = nav.Select(expr)
    While iterator.MoveNext()
    Dim nav2 As XPathNavigator = iterator.Current.Clone()
    nav2.MoveToFirstChild()
    ???
    nav2.MoveToNext()
    ???
    End While

    迭代器上的 Current 屬性返回節點集中的當前節點。它計算為 XPathNavigator 類的實例,并且可以使用 Clone 方法克隆。

    .NET 中的 XSL 概述

    XML 轉換是用戶定義的、試圖用另外的(等價的)語法表達給定文檔語義的算法。轉換過程包含基于樣式表的結構來呈現源文檔。樣式表是聲明性的用戶定義文檔,它包 含用來將一個文檔轉換為另一個文檔的規則集。XSL 是指為了表示 XML 文檔的樣式表而設計的元語言。XSL 文件最初被想像為 HTML 級聯樣式表 (CSS) 的 XML 對應物。鑒于此,XSL 被設計為可擴展的、用戶可定義的工具,該工具可以用 HTML 呈現 XML 文檔以便進行顯示。樣式表日益增長的復雜性以及 XML 架構的出現導致了 XSLT 的產生。目前,XSL 只是許多派生技術的一個總括性的術語,所有這些技術能夠更好地形容和實現將 XML 文檔樣式化的的原始思想。XSL 所包含的各種組件是在代碼中使用的實際軟件實體:XSLT、XPath 和 XSL 格式化對象 (XSLFO)。

    XSLT 程序是一個一般性的轉換規則集,其輸出可以是任何基于文本的語言,包括 HTML、RTF 等等。正如前文提到的那樣,XPath 是一種查詢語言,XSLT 程序可以利用它來選擇源 XML 文檔的特定部分。XPath 表達式的結果隨后由 XSLT 處理程序進行分析和闡述。通常,XSLT 處理程序對源文檔進行順序處理,但是如果要求訪問特定的節點組,則它會將該源文檔傳遞給 XPath。

    在 .NET Framework 中,XSLT 的核心類是 XslTransform。該類位于 System.Xml.Xsl 命名空間中,并實現了 XSLT 處理程序。可以采取兩個步驟來使用該類:首先在處理程序中加載樣式表,然后根據需要向任意多的源文檔應用轉換。XslTransform 類只支持 XSLT 1.0 規范。圖 8 中的 C# 代碼實現了一個命令行 XSLT 轉換器。它采用三個命令行參數(XML 源、XSLT 樣式表和輸出文件)來設置處理程序并且將轉換結果保存到輸出文件中。

    XslTransform 類

    XslTransform 類提供了兩個特定于其活動的方法 — Load 和 Transform。該類只有在轉換操作期間才能保證以線程安全的方式進行操作。換句話說,盡管該類的實例可以由多個線程共享,但只有 Transform 方法才可以從多個線程中安全地調用。Load 方法不是線程安全的。Transform 方法讀取共享狀態,并且可以從多個線程中并發運行。圖 9 顯示了該類的內部體系結構的一部分。在加載樣式表之后,XSLT 處理程序需要修改它的狀態以反映所加載的文檔。該操作不會在由鎖定語句創建的虛擬邊界中以原子方式發生。因此,并發運行的線程理論上可以訪問同一個 XSLT 處理程序實例,從而破壞數據一致性。加載操作是線程敏感的,因為它改變了對象的全局狀態。

    圖 9 XSL Transform 類

    在 .NET Framework 的版本 1.0 中,XslTransform 類附加了鏈接請求權限集。鏈接請求指定直接調用方運行代碼必須具有的權限。調用方權限在即時編譯期間進行檢查:

    [PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")]
    public sealed class XslTransform
    { ??? }

    XslTransform 類的權限集屬性由名稱表示,并且指向內置的權限集之一 — FullTrust。這對用戶來說意味著什么呢?只有對所有本地資源都具有完全受信任訪問權限的調用方(該檢查涉及直接調用方,而不是調用方的調用方)才 可以安全地調用到 XSLT 處理程序中。例如,如果您通過網絡共享調用 XSL 處理程序,則會引發安全異常。在 .NET Framework 的版本 1.1 中,該權限集已經被移除。

    在 .NET Framework XSLT 處理程序的總體行為中,可以明確地標識三個階段:樣式表文檔的加載、內部狀態的設置和轉換。頭兩個階段發生在 Load 方法的上下文中。當然,在前面的 Load 調用成功終止之前,無法調用 Transform 方法。Load 方法總是同步工作,以便當它返回時,您可以確保加載步驟已經實際完成。您將不會收到任何指示操作失敗或成功的返回值。但是,每當 Load 方法發生什么錯誤時,都會引發一些異常。特別地,如果您指向一個丟失的樣式表,則將得到 FileNotFoundException 類型的異常;如果 XSLT 腳本包含某些錯誤,則將得到 XsltCompileException 類型的更一般的異常。XsltCompileException 異常提供了樣式表中發生錯誤的行位置和編號。

    可以從四個不同的源加載輸入樣式表:URL、XML 讀取器、XPathDocument 和 XPathNavigator。不管是哪個源,Load 方法的第一個操作都是將該源表示為一個 XPathNavigator 對象。樣式表必須進行編譯,并且,考慮到編譯器的體系結構,導航器是非常有效的對象。“編譯”是這樣一個過程,它簡單地從原始樣式表中提取一些信息,并將 其存儲在方便的數據結構中以便進一步使用。這些數據結構的整個集合稱為 XSLT 處理程序的狀態。圖 10 顯示了 Load 方法的流程。

    圖 10 Load 方法流程

    樣式表編譯器用從源中讀取的數據填充三個內部數據結構。作為已編譯樣式表對象引用的對象表示樣式表內容的一種索引。其他兩個對象是表和操作,前者包含要執行的 XPath 查詢的編譯版本,后者是各種模板所需的操作。

    Transform 方法至少采用兩個顯式參數 — 源 XML 文檔和輸出流,再加上幾個隱式參數。當然,已編譯的樣式表對象是隱式輸入參數之一。第二個隱式參數是 XslTransform 的 XmlResolver 屬性(該屬性專門用于解析外部資源)的內容。Transform 方法還可以采用第三個顯式參數 — 類 XsltArgumentList 的對象。該參數包含被用作轉換過程的輸入的命名空間限定參數。

    XML 源文檔被標準化為 XPathNavigator,并且向下傳遞給 XSLT 處理程序。有趣的是,Transform 方法具有兩種類型的重載。其中一些重載作為 void 方法工作,并且只是寫入指定的流。其他重載作為函數工作,并且明確返回一個 XML 讀取器對象。正如我稍后將討論的那樣,該功能提供了一個非常有趣的機會:實現異步 XSLT 轉換。在圖 11 中,可以看到 Transform 方法的執行流。

    圖 11 Transform 方法

    Transform 方法還使您可以使用 XsltArgumentList 類的實例向樣式表傳遞參數。在以這種方式向 XSLT 腳本傳遞參數時,您無法指定哪個模板調用將實際使用這些參數。您只是以全局方式將參數傳遞給 XSLT 處理程序。負責處理模板的內部模塊隨后將根據需要讀取和導入這些參數:

    XsltArgumentList args = new XsltArgumentList();
    args.AddParam("MaxNumOfRows", "", 7);

    AddParam 方法在參數列表中創建了一個新項。該方法需要三個參數:參數名稱、命名空間 URI(如果該名稱由命名空間前綴限定)以及一個代表實際值的對象。不管您用來將參數值包裝到參數列表中的 CLR 類型如何,該參數值都必須對應于有效的 XPath 類型:字符串、布爾型、數字、節點片段和節點集。數字對應于雙精度類型,而節點片段和節點集等價于 XPathNavigators 和 XPath 節點迭代器。

    參數和擴展對象

    XsltArgumentList 不是基于集合的類。它不是派生自集合類,也沒有實現任何典型的列表接口(如 IList 或 ICollection)。XsltArgumentList 類是圍繞幾個哈希表生成的 — 一個用于存放 XSLT 參數,一個用于收集擴展對象。擴展對象是 .NET 對象的一個活動實例,它可以作為參數傳遞給樣式表。例如,可以用各種方式擴展 XSLT 腳本以獲得嵌入式 XPath 庫未提供的功能。XslTransform 類支持 <xsl:eval> 指令,該指令使您可以將 VBScript 插入到樣式表中。將自定義代碼嵌入到腳本中的替代方法是使用 <msxsl:script> 元素。該新指令支持托管語言并且提供對整個 .NET Framework 的訪問:

    <msxsl:script
    language = "language"
    implements-prefix = "prefix">
    ???
    </msxsl:script>

    受支持的語言包括 C#、Visual Basic 和 JScript?。Language 屬性不是強制性的,并且,如果未指定該屬性,則默認為 JScript。但是,Implements-prefix 屬性是強制性的。它聲明一個命名空間并且將用戶定義的代碼與它相關聯。該命名空間必須在樣式表中某處進行定義。此外,要使用 <msxsl:script> 指令,該樣式表必須包含以下命名空間:

    xmlns:msxsl=urn:schemas-microsoft-com:xslt

    要定義簡單腳本,需要在該樣式表的根中聲明額外的命名空間。例如:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:dino="urn:dino-scripts">

    該聲明是調用 <msxsl:script> 指令所需要的。該命名空間只是將某些由用戶定義的腳本組合在一起。現在,需要使用前綴“dino”來限定對 <msxsl:script> 塊中定義的任何函數的任何調用。在樣式表的體中,調用 <msxsl:script> 塊中定義的任何函數:

    <xsl:template match="lastname">
    <TD style="border:1px solid black">
    <xsl:value-of select="dino:PrepareName(., ../firstname)" />
    </TD>
    </xsl:template>

    如果您在參數的前后加上引號,則它們將被視為文字值。要確保托管函數收到節點值,請使用與用于 <xsl:value of> 指令的 select 屬性的表達式相同的表達式。

    <msxsl:script> 指令并不總是最佳的解決方案。它只支持作為 XSLT 處理程序的一部分導入的一組有限的命名空間。例如,您無法使用 System.Data 命名空間。腳本適合于一次性的操作,例如,分析字符串或檢索當前時間。至于更為強大的替代解決方案,請考慮擴展對象。

    擴展對象只是一個具 有一些公共方法的托管類。唯一的要求是可調用的方法接受 XPath 類型的參數或可以強制轉換到該類型的參數。與嵌入式腳本(它們被自然地定義在樣式表的體中)不同,擴展對象是必須以某種方式插入到樣式表中的外部資源。擴 展對象參數必須按照以下代碼所示進行傳遞:

    ExtensionObject o = new ExtensionObject();
    // *** set properties on the object if needed
    XsltArgumentList args = new XsltArgumentList();
    args.AddExtensionObject("urn:dino-objects", o);
    XslTransform xslt = new XslTransform();
    xslt.Transform(doc, args, writer);

    在 XSLT 腳本中,可以像使用嵌入式腳本那樣引用擴展對象上的方法。在下面的代碼片段中,DoSomething 是與帶有“dino”前綴的命名空間相關聯的擴展對象上的方法:

    <xsl:template match="lastname">
    <TD style="border:1px solid black">
    <xsl:value-of select="dino:DoSomething(., ../firstname)" />
    </TD>
    </xsl:template>

    擴展對象的方法被作為靜態方法調用進行處理,這意味著如果您具有多個帶有相同方法名稱的對象,則最好使用不同的命名空間。

    使用擴展對象比使用嵌入式腳本更為可取,這至少有兩個原因。首先,擴展對象提供了好得多的代碼封裝,更不用提實現類重用的可能性以及可以使用任何托管類型這一事實。其次,最后可以得到能夠從更加無縫的代碼維護中受益的更緊湊的分層樣式表。

    異步 XSLT

    Transform 方法具有幾個能夠返回 XML 讀取器的重載:

    XmlReader Transform(XPathNavigator input, XsltArgumentList args);
    XmlReader Transform(IXPathNavigable input, XsltArgumentList args);

    這些重載的簽名和行為與其他重載稍有不同。首先,輸入文檔必須是 XPathNavigator 或 XPathDocument。更重要的是,這些方法不接受任何代表輸出流的參數。實際上,轉換過程的輸出不是寫出到流中,而是在流中創建并且通過 XML 讀取器返回給用戶。

    .NET Framework 中的整個 XSLT 過程通過創建一個中間數據結構(輸入導航器)工作,在該數據結構中,樣式表的內容被用作底層的基礎。在該樣式表源中發現的任何 <xsl> 標記都被替換為展開的文本或產生自嵌入式模板的任何調用序列。最終輸出看起來像是已編譯的程序,其中直接語句與子例程調用交替出現。這些語句被稱為輸出記 錄,而模板則充當子例程的角色。當 Transform 方法獲得可以寫入的輸出流時,XSLT 處理程序遍歷所有記錄并將文本刷新到流中。如果已經請求 XML 讀取器,則處理程序會創建某個內部讀取器類的實例,并將其返回給調用方。在調用方顯式請求讀取緩存的輸出記錄之前,不會執行任何轉換(參見圖 12)。

    圖 12 XSL 轉換過程

    當 Transform 方法返回時,讀取器處于其初始狀態,這意味著它尚未針對讀取操作進行初始化。每當您從讀取器中彈出一個元素時,都將正確地展開并返回一個新的輸出記錄。這 樣,您可以完全控制轉換過程,并且可以實現許多奇特的功能。例如,您可以向用戶提供反饋,基于運行庫條件和用戶角色丟棄節點,或者使該過程在輔助線程上異 步發生。有關異步轉換的示例,請參見本文的代碼下載。

    <asp:xml> 標記

    在結束本文之前,我希望考察 一個由 <asp:xml> 標記標識的特殊 ASP.NET 服務器控件。該控件是 XslTransform 類的聲明性對應物。可以使用 XML 服務器控件在 Web 頁中嵌入 XML 文檔。在需要可供客戶端使用的 XML 數據島時,使用該控件很方便。數據島是 HTML 頁中引用或包含的 XML 數據。XML 數據可以用內聯方式包含在 HTML 中,也可以存儲在外部文件中。通過將該控件的能力與執行特定于瀏覽器的轉換的樣式表相結合,可以將服務器端 XML 數據轉換為不受瀏覽器影響的 HTML。例如,以下代碼嵌入指定的 XML 文件的內容,就像由該頁中的樣式表進行轉換一樣:

    <div>
    <asp:xml runat="server" id="xmldata"
    documentsource="data.xml"
    transformsource="ie5.xsl" />
    </div>

    XML 服務器控件可以通過編程方式進行配置,并且通過字符串(DocumentContent 屬性)以及通過 XmlDocument 對象(Document 屬性)接受源 XML。轉換元素可以通過指向 XSL 文件的 URL 或者通過 XslTransform 類的實例(Transform 屬性)提供。如果需要,還可以使用 TransformArgumentList 屬性指示參數。該組件與 HttpBrowserCapabilities 類一起,為常見需要(數據驅動 Web 頁和特定于瀏覽器的輸出)提供了一種了不起的解決方案。

    請注意,只有格式規范的 XML 數據才能與 <asp:xml> 控件一起使用。更簡單地,如果需要刷新任何文件的內容,則可以使用 Response.WriteFile 方法。

    小結

    在 本文中,我將 XPath 作為在托管應用程序中執行 XML 查詢的語言加以分析,并且討論了其實現的幾個方面。在 .NET Framework 中,XPath 運行庫為其他令人困惑的部分(其中第一個是 XSLT)提供了公用基礎結構。我還分析了 XSLT 處理程序的關鍵方面,并且提供了它的幾個有趣的應用,例如異步處理和 ASP.NET 控件。

    有關背景信息,請參閱:
    Applied XML Programming for Microsoft .NET by Dino Esposito (Microsoft Press, 2002)
    Essential XML Quick Reference: A Programmer's Reference to XML, XPath, XSLT, XML Schema, SOAP, and More by Aaron Skonnard and Martin Gudgin (Addison-Wesley, 2001)
    XPathNavigator over Different Stores
    MSDN Web Services Developer Center

    轉載于:https://www.cnblogs.com/chenying99/archive/2011/03/10/1980209.html

    總結

    以上是生活随笔為你收集整理的通过 .NET Framework 中的 XPath 和 XSLT API 方便地操作 XML 数据的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。