DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> XML 解析處理利器:基於 Xalan 的 XSLT2.0 和 XPath2.0 實現
XML 解析處理利器:基於 Xalan 的 XSLT2.0 和 XPath2.0 實現
編輯:XML詳解     

什麼是 XSLT ?

  XSL(eXtensible Stylesheet Language) -- 可擴展標記語言,主要用於將一個 XML 文檔轉換為另外的文檔(XML 文檔、Html 文檔),以及定義轉換後的文檔的顯示外觀。XSL 實際上包含了 3 種語言:XSL 轉換 (XSL Transformations,XSLT)、XML 路徑語言 (XPath) 和 XSL 格式化對象 (XSL-FO),其中 XSLT 主要用於將一個 XML 文檔轉換為其他的 XML 文檔或是其它類型的文檔;XPath 主要在 XSLT 和 XPointer 中使用,用於識別、選擇、匹配 XML 文檔中的各個組成部分,包括元素、屬性、文本內容;XSL-FO 定義了許多 XML 標記,這些標記描述了應如何顯示內容,XSL-FO 的一個主要應用就是將 XML 文檔轉換為 PDF 文件。

  XSLT 是 XSL 標准中最重要的部分,通常我們所說的 XSL 就是指 XSLT,接下來介紹 XSLT 和 XPath。

  XSLT 概述

  XML 將數據和顯示分開,XML 文檔用於表示數據,而要顯示文檔中的數據,就要給 XML 文檔添加樣式信息,一種選擇是使用 CSS(Cascading Style Sheets,層疊樣式表),另一種選擇就是使用 XSLT。XSLT 比 CSS 要復雜的多,功能也更加強大。CSS 不能對源 XML 文檔的數據進行計算、整理和排序,而這些在 XSLT 中可以很容易地實現。

  使用 XSLT,可以根據顯示的需要將同一份 XML 文檔轉換成多種類型的文檔,例如,要在 PC 的浏覽器中浏覽數據,可以將 XML 文檔轉換為 Html 文檔;要在手持設備中浏覽數據,可以將 XML 文檔轉換為符合手持設備顯示的文檔。利用 XSLT 轉換 XML 文檔,可以向輸出文檔中添加新的元素,或者刪除一些元素,重新安排元素並對元素進行分類,測試並確定顯示哪些元素等。

  1999 年 11 月 16 日,W3C 組織發布了 XSLT 1.0 的推薦標准,由於 XSLT 依賴於 XPath, 所以在同一天,W3C 組織也發布了 XPath 1.0 的推薦標准。讀者可以從下面的兩個網址查看 XSLT 和 XPath 推薦標准的內容:

  http://www.w3.org/TR/xslt

  http://www.w3.org/TR/xpath

  下面我們通過簡單的例子,來向大家展示一下如何應用 XSLT 對一個 XML 文檔進行解析轉換操作。首先給出一個 XML 文檔:

  清單 1. HelloWorld.XML 文件內容

 <?XML version="1.0" encoding="utf-8" ?> 
 <?XML-stylesheet type="text/xsl" href="helloworld.xsl" ?> 
 <helloworld> 
 <title>Welcome to XSLT world!</title> 
 <content>Hello! Welcome here!</content> 
 </helloworld> 

  在 XML 聲明之後的處理指令,表明該 XML 文檔關聯了一個名為 helloworld.xsl 的 XSLT 樣式表文件。IE 浏覽器內嵌的 XML 處理器在分析這個文檔時,會調用相應的 XSLT 處理器對該文檔進行轉換。以下是 helloworld.xsl 的樣式表文件內容:

  清單 2. Helloworld.xsl 文件內容

 <?XML version="1.0" encoding="utf-8"?> 
 <xsl:stylesheet version="1.0" 
 XMLns:xsl="http://www.w3.org/1999/XSL/Transform"> 
 
 <xsl:template match="/"> 
 <Html> 
 <xsl:apply-templates/> 
 </Html> 
 </xsl:template> 
 
 <xsl:template match="helloworld"> 
 <head><title> 
 <xsl:value-of select="title"/> 
 </title></head> 
 <body> 
 <xsl:value-of select="content"/> 
 </body> 
 </xsl:template> 
 </xsl:stylesheet> 

  在 IE 浏覽器中我們可以看到如下的效果:

  圖 1. HelloWorld XSLT 解析效果預覽

  從上圖中可以看到,XSLT 文件將 XML 文件中的 title 元素轉換為 HTML 中的 title 元素,將 XML 文件中的 content 元素轉換為 Html 中的 body 元素。

  XSLT 處理器在對 XML 文檔進行轉換時,根據指定的樣式表文檔來輸出結果文檔。XSLT 對源文檔、結果文檔和樣式表文檔使用同樣的數據模型來操作,也就是采用同樣的樹狀結構。不過要注意的是,處理指令和注釋在樣式表中被忽略;樣式表被看做是既沒有處理指令節點,又沒有注釋節點的樣式表樹。

  XSLT 處理器在構造結果樹時,可以對源文檔樹進行過濾、修改及添加其他的內容,且結果樹的結構可以和源文檔樹的結構完全不同。

  XSLT 處理器按照指定的樣式表文檔,將源文檔樹轉換為結果樹的示意圖,如下圖所示:

  圖 2. XSLT 處理器工作流程圖

    查看原圖(大圖)

  使用 Xalan 處理器進行 XSLT 處理操作

  在 Apache 官方站點上學習 Xalan 相關知識

  讀者可以在 apache 官方站點上下載 Xalan 資源包、查看 Xalan 教程等,這樣可以幫助讀者對 Xalan 的使用及相其設計有更多的認識。

  Xalan 首頁地址:http://xalan.apache.org/

  Xalan For Java 首頁地址:http://XML.apache.org/xalan-j/

  Xalan API 在線查看:http://XML.apache.org/xalan-j/apidocs/index.Html

  Xalan 是一個非常流行的開放源代碼的 XSLT 解析處理器,它是 apache 下的一個開源項目,實現了 W3C XSLT 1.0 和 XPath 1.0 規范。Xalan 提供了 Java 和 C++ 的版本,本文使用的 Xalan 版本的 Xalan-Java 2.7.1。

  Xalan 即可以作為一個 XSLT 工具以命令行的方式使用,也可以作為一個模塊在其他應用程序中使用。讀者可以在 http://www.apache.org/dyn/closer.CGI/XML/xalan-j 上下載最新版本的 Xalan 處理器。

  在下載解壓縮後的目錄中,有一個 xalan.jar,這就是 Xalan 處理器,也是實現了 XSLT 和 XPath 規范的類庫。在 docs 目錄下的 commandline.Html 文件介紹了如何以命令行的方式使用 Xalan 處理器。

  本文通過在 Java 程序中調用相關類庫來使用 Xalan 進行 XML 文件的解析轉換操作。為了便於介紹 Xalan 的相關知識,編寫如下的示例 XML 文檔:

  清單 3. 示例 XML 文檔

 <?XML version="1.0"?> 
 <doc> 
 <name first="David" last="Marston">David Marston</name> 
 <name first="David" last="Bertoni">David Bertoni</name> 
 <name first="Donald" last="Leslie">Donald LeslIE</name> 
 <name first="Emily" last="Farmer">Emily Farmer</name> 
 <name first="Joseph" last="Kesselman">Joseph Kesselman</name> 
 <name first="Myriam" last="Midy">Myriam Midy</name> 
 <name first="Paul" last="Dick">Paul Dick</name> 
 <name first="Stephen" last="Auriemma">Stephen AurIEmma</name> 
 <name first="Scott" last="Boag">Scott Boag</name> 
 <name first="Shane" last="Curcuru">Shane Curcuru</name> 
 </doc> 

  下面舉例說明如何使用 Xalan 來實現利用 XSLT 和 XPath 進行 XML 文件的解析操作,我們有如下 Java 調用 Xalan 來使用 XPath 進行 XML 文檔解析的示例代碼,該段程序找出所有 first 以 D 開發的名字列表:

  清單 4. 使用 Xalan 進行 XML 解析處理示例代碼

 public class ApplyXPath 
 { 
 protected String filename = null; 
 protected String xpath = null; 
 
 /** Process input args and execute the XPath. */ 
 public void doMain(String[] args) throws Exception 
 { 
 filename = args[0]; 
 xpath = args[1]; 
 
 if ((filename != null) && (filename.length() > 0) 
 && (xpath != null) && (xpath.length() > 0)) 
 { 
 // Tell that we're loading classes and parsing, so the time it 
 // takes to do this doesn't get confused with the time to do 
 // the actual query and serialization. 
 System.out.println("Loading classes, parsing " 
 +filename+", and setting up serializer"); 
  
 // Set up a DOM tree to query. 
 InputSource in = new InputSource(new FileInputStream(filename)); 
 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 
 dfactory.setNamespaceAware(true); 
 Document doc = dfactory.newDocumentBuilder().parse(in); 
  
 // Set up an identity transformer to use as serializer. 
 Transformer serializer = TransformerFactory.newInstance().newTransformer(); 
 serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); 
 
 // Use the simple XPath API to select a nodeIterator. 
 System.out.println("Querying DOM using "+xpath); 
 NodeIterator nl = XPathAPI.selectNodeIterator(doc, xpath); 
 
 // Serialize the found nodes to System.out. 
 System.out.println("<output>"); 
  
 Node n; 
 while ((n = nl.nextNode())!= null) 
 { 
 if (isTextNode(n)) { 
 // DOM may have more than one node corresponding to a 
 // single XPath text node. Coalesce all contiguous text nodes 
 // at this level 
 StringBuffer sb = new StringBuffer(n.getNodeValue()); 
 for ( 
 Node nn = n.getNextSibling(); 
 isTextNode(nn); 
 nn = nn.getNextSibling() 
 ) { 
 sb.append(nn.getNodeValue()); 
 } 
 System.out.print(sb); 
 } 
 else { 
 serializer.transform(new DOMSource(n), 
 new StreamResult(new OutputStreamWriter(System.out))); 
  
 } 
 System.out.println(); 
 } 
 System.out.println("</output>"); 
 } 
 else 
 { 
 System.out.println("Bad input args: " + filename + ", " + xpath); 
 } 
 } 
  
 /** Decide if the node is text, and so must be handled specially */ 
 static boolean isTextNode(Node n) { 
 if (n == null) 
 return false; 
 short nodeType = n.getNodeType(); 
 return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE; 
 } 
 
 /** Main method to run from the command line. */ 
 public static void main (String[] args) 
 throws Exception 
 { 
 ApplyXPath app = new ApplyXPath(); 
 app.doMain(new String[]{"foo.XML","/doc/name[starts-with(@first,'D')]"}); 
 } 
   
 } 

  此段程序通過 XPath 進行 XML 文檔解析操作,並將解析結果序列化後輸出至控制台。運行示例代碼,我們可以得到如下的運行結果,即得到所有 first 以 D 開頭的名字列表。

  清單 5. XPath 函數 starts-with 示例運行結果

 Loading classes, parsing foo.XML, and setting up serializer 
 Querying DOM using /doc/name[starts-with(@first,'D')] 
 <output> 
 <name first="David" last="Marston">David Marston</name> 
 <name first="David" last="Bertoni">David Bertoni</name> 
 <name first="Donald" last="Leslie">Donald LeslIE</name> 
 </output> 

  那如果我們要找出所有 first 以 d 結尾的名字列表怎麼辦呢?我們把 starts-with 改為 ends-with,運行示例代碼,得到如下的錯誤信息:

  清單 6. XPath 包含不支持函數運行結果

 Loading classes, parsing foo.XML, and setting up serializer 
 Querying DOM using /doc/name[ends-with(@first,'D')] 
 Exception in thread "main" Javax.XML.transform.TransformerException: 找不到函數:ends-with 
 at org.apache.xpath.compiler.XPathParser.error(XPathParser.Java:610) 
 at org.apache.xpath.compiler.XPathParser.FunctionCall(XPathParser.Java:1507) 
 at org.apache.xpath.compiler.XPathParser.PrimaryExpr(XPathParser.Java:1446) 
 at org.apache.xpath.compiler.XPathParser.FilterExpr(XPathParser.Java:1345) 
 at org.apache.xpath.compiler.XPathParser.PathExpr(XPathParser.Java:1278) 
 at org.apache.xpath.compiler.XPathParser.UnionExpr(XPathParser.Java:1236) 
 at org.apache.xpath.compiler.XPathParser.UnaryExpr(XPathParser.Java:1142) 
 at org.apache.xpath.compiler.XPathParser.MultiplicativeExpr(XPathParser.Java:1063) 
 at org.apache.xpath.compiler.XPathParser.AdditiveExpr(XPathParser.Java:1005) 
 at org.apache.xpath.compiler.XPathParser.RelationalExpr(XPathParser.Java:930) 
 at org.apache.xpath.compiler.XPathParser.EqualityExpr(XPathParser.Java:870) 
 at org.apache.xpath.compiler.XPathParser.AndExpr(XPathParser.Java:834) 
 at org.apache.xpath.compiler.XPathParser.OrExpr(XPathParser.Java:807) 
 at org.apache.xpath.compiler.XPathParser.Expr(XPathParser.Java:790) 
 at org.apache.xpath.compiler.XPathParser.PredicateExpr(XPathParser.Java:1954) 
 at org.apache.xpath.compiler.XPathParser.Predicate(XPathParser.Java:1936) 
 at org.apache.xpath.compiler.XPathParser.Step(XPathParser.Java:1726) 
 at org.apache.xpath.compiler.XPathParser.RelativeLocationPath(XPathParser.Java:1635) 
 at org.apache.xpath.compiler.XPathParser.LocationPath(XPathParser.Java:1597) 
 at org.apache.xpath.compiler.XPathParser.PathExpr(XPathParser.Java:1317) 
 at org.apache.xpath.compiler.XPathParser.UnionExpr(XPathParser.Java:1236) 
 at org.apache.xpath.compiler.XPathParser.UnaryExpr(XPathParser.Java:1142) 
 at org.apache.xpath.compiler.XPathParser.MultiplicativeExpr(XPathParser.Java:1063) 
 at org.apache.xpath.compiler.XPathParser.AdditiveExpr(XPathParser.Java:1005) 
 at org.apache.xpath.compiler.XPathParser.RelationalExpr(XPathParser.Java:930) 
 at org.apache.xpath.compiler.XPathParser.EqualityExpr(XPathParser.Java:870) 
 at org.apache.xpath.compiler.XPathParser.AndExpr(XPathParser.Java:834) 
 at org.apache.xpath.compiler.XPathParser.OrExpr(XPathParser.Java:807) 
 at org.apache.xpath.compiler.XPathParser.Expr(XPathParser.Java:790) 
 at org.apache.xpath.compiler.XPathParser.initXPath(XPathParser.Java:129) 
 at org.apache.xpath.XPath.<init>(XPath.Java:178) 
 at org.apache.xpath.XPathAPI.eval(XPathAPI.Java:236) 
 at org.apache.xpath.XPathAPI.selectNodeIterator(XPathAPI.Java:128) 
 at org.apache.xpath.XPathAPI.selectNodeIterator(XPathAPI.Java:108) 
 at ApplyXPath.ApplyXPath.doMain(ApplyXPath.Java:73) 
 at ApplyXPath.ApplyXPath.main(ApplyXPath.Java:123) 

  此錯誤信息告訴我們,找不到名為 ends-with 的函數。為什麼會這樣呢?事實上,在 XSLT 1.0 規范中,是不提供 ends-with 字符串處理函數的,如果要使用這個函數,則要進一步學習 XSLT 2.0 規范。

  XSLT 2.0 和 XSLT 1.0 比較

  從 XSLT 1.0 和 XPath 1.0 推薦標准發布以來,XSLT 在很多領域都得到了應用,很多人開始使用 XSLT 和 XML 代替 Html 開發,然而,在實際應用過程中,XSTL 的一些不足也逐漸顯現出來,例如沒有提供內置的分組功能,只提供了少量的內置函數而又不支持自定義函數等,這些都限制了 XSLT 的進一步應用。為了擴展 XSLT 的功能,不少廠商和開源組織開始使用專有的技術對 XSLT 進行擴展,以便在轉換中提供更為便利、豐富的功能。W3C 也意識到 XSLT 的一些問題,於是從 2001 年開始制定 XSLT 2.0 規范,經過漫長的談論、修訂,XSLT 1.0 推薦標准終於在 2007 年 1 月 23 日正式發布,同一天也發布了 XPath 2.0 推薦標准。

  與 XSLT 1.0 不同的是,XSLT 2.0 家族現在包含 6 個規范,它們是:XSL Transformations (XSLT) Version 2.0、XML Path Language (XPath) 2.0、XQuery/XPath Data Model (XDM)、Xquery 1.0 and XPath 2.0 Formal Semantics、Xquery 1.0 and XPath 2.0 Functions and Operators 以及 XSLT 2.0 and Xquery 1.0 Serialization 標准。

  XPath 2.0

  XPath 2.0 現在是 XSLT 2.0 和 XQurey 1.0 共同的基礎,這兩種語言都使用 XPath 作為核心的查詢引摯。XPath 2.0 和 XPath 1.0 之間的區別包括:

  基於序列而非節點集的新的數據模型

  綁定變量的能力,XPath 1.0 的變量綁定在宿主語言 (XSLT) 中

  完全支持 XML Schema 數據類型

  最重要的是,提供了許多的新功能,這其中包括正則表達式、日期與時間處理以及大量的功能強大的函數集合 , 包括數值函數、字符串函數、布爾值函數、序列操作的函數以及聚集函數。

  擴展 Xalan 支持 XPath 2.0 處理函數

  雖然 W3C 組織在 2007 年 1 月發布了 XSLT 2.0 和 XPath 2.0 的推薦規范,但是到目前為止,apache Xalan 依然不支持 XPath 2.0 的處理函數,如果讀者想要使用 XPath 2.0 中的函數,則要對 Xalan 的函數庫進行擴展,接下來將下大家介紹如何擴展 Xalan 的內置函數庫。

  XPath 2.0 與 XPath 1.0 函數支持對比

  要為 Xalan 擴展支持 XPath 2.0 所支持的函數,首先得清楚 XPath 2.0 和 XPath 1.0 分別包括了哪些函數,這裡給出一個對照表,限於篇幅原因,我們僅以字符串處理函數為例,其它類型的函數信息可以在如下地址得到 http://www.w3.org/TR/xpath-functions/。

  表 1. XPath 2.0 與 XPath 1.0 字符串處理函數對照表

函數名稱 XPath 2.0 支持情況 XPath 1.0 支持情況 contact 支持 支持 starts-with 支持 支持 contains 支持 支持 substring-before 支持 支持 substring-after 支持 支持 substring 支持 支持 string-length 支持 支持 normalize-space 支持 支持 translate 支持 支持 string-join 支持 不支持 ends-with 支持 不支持 normalize-unicode 支持 不支持 upper-case 支持 不支持 lower-case 支持 不支持 encode-for-uri 支持 不支持 iri-to-uri 支持 不支持 escape-Html-uri 支持 不支持 matches 支持 不支持 replace 支持 不支持 tokenize 支持 不支持

  我們可以從這張表中看出,顯然 XPath 2.0 提供的內置函數功能更為強大,如果該函數規范全部實現,勢必會為 XSLT 開發者帶來極大的便利。

  Xalan 系統結構分析

  要為 Xalan 實現 XSLT 2.0 內置函數規范,必須要先對 Xalan 的體系結構有一個系統的認識和理解,才能正確的在其基礎之上為其實現 XSLT 2.0 的相應規范。

  圖 3. XSLT 抽象處理模型示意圖

  這個圖展示了 XSLT 抽象處理模型,XSLT 描述了把 XML 源結構樹轉換為目標結構樹的轉換規則。

  Xalan 的主要的功能接口是在 Javax.XML.transform 接口包中定義的。這些接口定義了一個標准的並且功能強大的用來進行基於樹形結構轉換的功能接口集。

  Xalan 的內部設計為分為四個主要的模塊和多個小模塊,這四個主要的模塊分別是:

  Org.apache.xalan.processor

  該模塊進行樣式表的處理,並且提供了 Xalan 的主要功能入口。

  Org.apache.xalan.templates

  該模塊定義了樣式表結構,包括 Stylesheet 對象,模板元素指令以及屬性值模塊。

  Org.apache.xalan.transformer

  該模塊將源結果樹應用於模板,並生成目標結果樹。

  Org.apache.xpath

  該模塊處理 XPath 表達式及 XSLT Match 表達式。

  除此之外,Xalan 還實現了依賴於 SAX2 和 DOM 的整個 Javax.XML.transform 接口包。

  圖 4. Xalan 工作流程圖

  Xalan 還有一個包含所有公共基礎類的包,這個包裡面有所有的 XML 基礎類(例如 QName),以及一些有用的功能輔助類,例如 StringToIntTable 類。下面這張類圖中,箭頭表示調用關系,所有的包都可以調用 SAX2 和 DOM 包。

  圖 5. Xalan 模塊依賴關系圖

    查看原圖(大圖)

  除了以上類包,Xalan 還有其它幾個主要的模塊:

  Org.apache.xalan.clIEnt

  該模塊包含一個客戶端 Applet, 我估計這個包可能會被移到示例包中。

  Org.apache.xalan.extensions

  該模塊包含實現 Xalan 擴展機制的所有類,該模塊允許在樣式表中調用 Java 代碼和腳本。

  Org.apache.xalan.lib

  該模塊是 Xalan 內置的擴展包,它實現了例如 Redirect 的功能擴展模塊。

  Org.apache.xalan.res

  這個包裡面是 Xalan 所需要的資源文件,例如錯誤信息資源文件。

  Org.apache.xalan.trace

  這個包裡面包含允許調用者為轉換器添加打印輸出的類和接口。

  Org.apache.xalan,xslt

  這個包裡面包含 Xalan 的命令行處理器。

  要為 Xalan 實現 XPath 2.0 提供的內置函數,我們需要擴展 org.apache.xpath 功能模塊。

  XPath 模塊分析

  在最新版本的 Xalan 中,xpath 模塊已經從 xalan 包中提出來了,被放入 org.apache 包中,來強調這個包雖然依賴於 Xalan utils 模塊,但是可以被 XSLT 處理引摯單獨進行調用的意圖。

  XPath 處理模塊首先將 XPath 字符串轉換成為表達式樹,並通過調用 XPath 的 execute 方法來執行該表達式樹。這個包中的主要類有:

  XPath 類:該類用來表示一個已經經過編譯的 XPath,主要的處理函數是 XObject execute(XPathContext xctxt,Node contextNode,PrefixResolver namespaceContext)。

  XPathAPI 類:該類中的方法用以訪問底層的 XPath API。

  XPathContext 類:該類用來表示 XPath 的運行時執行上下文。

  DOMHelper 類:被用來處理 DOM 問題的助手類,可以作為特定的 DOM 實現基類。

  SourceTreeManager 類:源 XML 樹形結構管理類,該類中的方法可以解析和丟棄源 XML 樹形結構。

  Expression 類:所有表達式對象的基類,允許多態行為。

  XPath 模塊被設計成為兩個主要部件:編譯器及表達式對象集合。

  圖 6. XPath 模塊類圖

    查看原圖(大圖)

  該模塊最重要的是 axes 模塊,這個模塊實現了 DOM 2NodeIterator 接口,也就是說它允許 XPath 客戶端重載此操作或是替換此操作。

  XPath 2.0 函數實現實例

  下面具體講述為 Xalan 實現 XSLT 2.0 規范中的字符串處理函數 ends-with 的實現過程。從上面的 XPath 模塊類圖中我們可以看到,Xalan 的內置函數實現全部在 org.apache.xpath.functions 包中,我們要在此包中添加新的函數實現,接下來該講解如何一步步為 Xalan 添加一個新的內置函數實現,我們以前文提到的 ends-with 函數為例。

  XPath 編譯器中注冊函數

  要讓 XPath 編譯器在執行 XSLT 轉換操作時遇到 XPath,能正確解析並識別出 XPath 所包含的函數,我們需先要先在 XPath 編譯器中對此函數進行注冊。類 org.apache.xpath.compiler.KeyWords 中存放著 Xalan 實現的所有 XPath 函數名稱,我們在此類中添加如下一個新的變量,用以表示要進行實現的字符串函數 ends-with:

  清單 8. 函數關鍵字注冊

 /** ends-with function string. */ 
 public static final String FUNC_ENDS_WITH_STRING = "ends-with"; 

  添加完函數關鍵字後,還需指定該函數的實現類以及相應的映射關系,這部分實現在 org.apache.xpath.compiler.FunctionTable 中。我們在此類中為函數 ends-with 添加一個唯一的函數 ID 值。

  清單 9. 注冊函數 ID 值

 /** The 'ends-with()' id. */ 
 public static final int FUNC_ENDS_WITH = 37; 

  XPath 1.0 規范中有 37 個函數,最大的函數 ID 值為 36( 從 0 開始計數 ),所以我們把 ends-with 的 ID 值設為 37。另外,還需指定該函數的具體實現類,這需要在變量 Class m_functions[] 和 HashMap m_functionID 中添加映射來進行實現。

  清單 10. 添加函數實現映射

 m_functions[FUNC_ENDS_WITH] = 
 org.apache.xpath.functions.FuncEndsWith.class; 
 
 m_functionID.put(KeyWords.FUNC_ENDS_WITH_STRING, 
 new Integer(FunctionTable.FUNC_ENDS_WITH)); 

  這樣,我們就成功把函數 ends-with 與函數實現類 org.apache.xpath.functions.FunEndsWith 類關聯了起來,接下來要做的就是實現該函數實現類。

  實現函數實現類

  Xalan 所有函數實現類需繼承 org.apache.xpath.functions.Function 類並實現 org.apache.xpath.Expression 接口,Xalan 本身已實現多個函數實現子類,分別為單參數函數實現(FunctionOneArg),雙參數函數實現類 (Function2Arg),三參數函數實現類 (Function3Arg)以及多參數函數實現類 (FunctionMultiArgs)。由於 ends-with 函數確定具有 2 個確定的參數,所以我們繼承 Function2Args,在 XObject execute (XPathContext xctxt) 函數中實現 ends-with 函數功能即可完成 XPath 2.0 規范函數 ends-with 的實現。代碼如下:

  清單 11. Ends-with 函數實現類

 import org.apache.xpath.XPathContext; 
 import org.apache.xpath.objects.XBoolean; 
 import org.apache.xpath.objects.XObject; 
 
 /** 
 * Execute the EndsWith() function. 
 * @xsl.usage advanced 
 */ 
 public class FuncEndsWith extends Function2Args 
 { 
 static final long serialVersionUID = 2194585774699567928L; 
 
 /** 
 * Execute the function. The function must return 
 * a valid object. 
 * @param xctxt The current execution context. 
 * @return A valid XObject. 
 * 
 * @throws Javax.XML.transform.TransformerException 
 */ 
 public XObject execute(XPathContext xctxt) 
 throws Javax.XML.transform.TransformerException 
 { 
 return m_arg0.execute(xctxt).xstr().endsWith(m_arg1.execute(xctxt).xstr()) 
 ? XBoolean.S_TRUE : XBoolean.S_FALSE; 
 } 
 } 

  由於該實現函數使用了 XString 對象的 endsWith 函數,所以我們還需要為 XString 類實現該功能函數,具體實現見參考資料所附代碼,在此就不再贅述了。

  函數實現測試

  在完成了 ends-with 函數實現後,需要測試其正確性。我們修改清單 4 中所附的示例代碼,將 start-with 函數替換成我們需要進行測試的 ends-with 函數,例如,我們利用 ends-with 函數找出所有 first 以 d 結束的名字列表:

  清單 12. Ends-with 函數測試代碼

 ApplyXPath app = new ApplyXPath(); 
 app.doMain(new String[]{"foo.XML","/doc/name[ends-with(@first,'d')]"}); 

  測試代碼運行結果如下:

  清單 13. 測試運行結果

 Loading classes, parsing foo.XML, and setting up serializer 
 Querying DOM using /doc/name[ends-with(@first,'d')] 
 <output> 
 <name first="David" last="Marston">David Marston</name> 
 <name first="David" last="Bertoni">David Bertoni</name> 
 <name first="Donald" last="Leslie">Donald LeslIE</name> 
 </output> 

  該段代碼通過調用我們實現的 XPath 2.0 規范函數 ends-with 來成功的找出所有 first 以 d 結束的名字列表。讀者可以通過本文介紹的方法,為 Xalan 實現更多的 XPath 2.0 規范函數。

  總結

  本文介紹了使用 XSLT 和 XPath 進行 XML 文檔轉換處理的相關知識,並講述了 XSLT 2.0 規范與 1.0 版本規范的改進之處。通過示例程序向大家講解了如何使用開源項目 Apache Xalan 來進行 XSLT 相關操作,另外,向讀者介紹了如何擴展 Xalan 使其支持 XPath 2.0 規范提供的內置函數,並通過示例進行驗證和論證。相信大家已經對 XSLT、XPath 以及 apache Xalan 使用及擴展有了基本的了解,可以使用 Xalan 進行 XML 文檔的轉換、解析處理操作。如果讀者希望進一步學習 XSLT 的知識,對 XSLT 和 apache Xalan 有更加深層次的理解和掌握,可以去 W3C 的官方網站查看 XSLT 規范細節,並嘗試為 Xalan 實現 XSLT 2.0 的所有規范細節,這將會是非常有意義和具有學習鍛煉價值的一件事。參考資料中列出一些有用的網頁鏈接,供讀者進行參考。

  另外,筆者已將替 Xalan 實現全部 XSLT 2.0 規范做為一個 apache Licence 下開放源代碼的項目進行開發,網址是 http://code.google.com/p/xslt2runner/,本文中的示例代碼可以在這個網址下找到,同時期望大家的關注和參與。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved