DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 樣式化樣式表以擴展XSLT(2)
樣式化樣式表以擴展XSLT(2)
編輯:XML詳解     

歡迎回來!

  您可能記得,我在上一篇文章展示了使用一個樣式表將一些新特性編譯進另一個樣式表這個概念。尤其是,我向您展示了如何編寫一個簡單的執行跟蹤的工具,它能自動修改樣式表,所以在它運行時,將在輸出文檔中生成注釋,同時還展示了由每個模板生成輸出文檔的哪個部分。

  然而,我在文章最後指出,我所開發的這個基本的版本功能還十分有限,並提出了可以改進的許多方面。在這篇專欄文章中,我將添加上一個版本所未有的一些特性,並將這種概念證明變成更實用的工具。

  注:我將假定您已經熟悉我上次開發的代碼,所以我將集中討論正在對該代碼所進行的更改。如果您沒有閱讀過 第 1 部分,那麼在繼續之前確實應該浏覽一下第 1 部分。

  在我原先的解決方案中所存在的限制之一是,在每個模板啟動,然後結束執行之後,它只報告 match 模式。事實上,不是每個模板執行都是 match 的結果。而是有些模板具有 name (或者附加有 name),並通過這個 name,使用 <xsl:call-template> 調用這些模板(至少有時是這樣)。並且有時有些模板具有重疊的 match 模式,具體運行哪一個模式取決於目前正在運行的樣式表的 mode 。

  所以我想修改上次編寫的樣式表 tracexsl.xsl ,使得在它的報告中包含這些細節。首先,我需要有一個模板告訴我更多有關它自身的情況,這意味著要使注釋生成器更具有“想象力”。我將檢查我所感興趣的每個屬性( match 、 name 和 mode )是否都存在,如果是,就顯示它。如果其中某個不存在,那麼我還是不打印它的名稱為好,這樣我可以區別出是沒有這個屬性還是它被設置成了空字符串。以下是我希望執行的序列:將模板開始(start-of-template)注釋生成器插入正在樣式化的模板:


 

清單 1. 插入模板開始注釋生成器

<tracexsl:text XML:space="preserve">
</tracexsl:text>
<tracexsl:comment>
<xsl:text>[TraceXSL Begin]</xsl:text>
<xsl:if test="@match">
<xsl:text> match="</xsl:text>
<xsl:value-of select="@match"/>
<xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="@name">
<xsl:text> name="</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="@mode">
<xsl:text> mode="</xsl:text>
<xsl:value-of select="@mode"/>
<xsl:text>"</xsl:text>
</xsl:if>
</tracexsl:comment>
<tracexsl:text XML:space="preserve">
</tracexsl:text>

  (請記住, tracexsl: 前綴被綁定到虛擬的名稱空間,由於我的用於樣式表的樣式表中有 <xsl:namespace-alias> 偽指令,所以當這些文字結果元素被復制到生成的樣式表時,這個前綴將重新綁定到正式的 XSLT 名稱空間。如果我直接使用 xsl: 前綴,則會立即執行這些元素而不是復制它們。)

  顯然,以並且可能應當用類似方式修改這個結束模板(end-template)注釋。

  現在我有更多有關運行 哪個模板的數據。但我仍然不知道它運行的 原因。遺憾的是,XSLT 沒有任何方式來詢問如何調用模板,或者當前的 mode 是什麼,所以我將必須多做些工作來顯示這些信息。


 

大多數模板的調用都是通過 <xsl:apply-templates> 進行的,而 mode 不變,所以我假定是這種情況。其它兩種可能情況是使用 <xsl:apply-templates> 而 mode 有所變化,或使用 <xsl:call-template> 。我可以使用應用在 <xsl:template> 元素的同樣技術,通過在輸出文檔中生成附加的注釋來報告這些操作……,但這次將把注釋放在我想要跟蹤的元素的外部,而不是將注釋插入元素內。

  這裡有一個模板,它在 <xsl:call-template> 出現時添加一條注釋。由於該注釋只應用於馬上要調用的下一個模板,所以我只在調用前生成一條注釋,而不是在調用前和調用後各生成一條注釋。

  清單 2. 當出現 <xsl:call-template> 時生成注釋

<xsl:template match="xsl:call-template">
<tracexsl:text XML:space="preserve">
</tracexsl:text>
<tracexsl:comment>
<xsl:text>[TraceXSL] CALL NAME="</xsl:text>
<xsl:value-of select="@name"/>
<xsl:text>"</xsl:text>
</tracexsl:comment>
<tracexsl:text XML:space="preserve">
</tracexsl:text>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

  以下是針對 mode 的更改生成注釋的模板。我確實希望只有當 mode 的確更改為新值時,我才進行報告 — 並在我跳出 <xsl:apply-templates> 調用時,報告它被恢復成什麼了 — 但我還沒有找到一種好的方法來做這件事。如果您找到了,請告訴我,以便我們更新這篇文章!

清單 3. 生成針對 mode 更改的注釋

<xsl:template match="xsl:apply-templates[@mode]">
<tracexsl:text XML:space="preserve">
</tracexsl:text>
<tracexsl:comment>
<xsl:text>[TraceXSL] APPLY MODE="</xsl:text>
<xsl:value-of select="@mode"/>
<xsl:text>"</xsl:text>
</tracexsl:comment>
<tracexsl:text XML:space="preserve">
</tracexsl:text>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<tracexsl:text XML:space="preserve">
</tracexsl:text>
<tracexsl:comment>
<xsl:text>[TraceXSL] END MODE="</xsl:text>
<xsl:value-of select="@mode"/>
<xsl:text>"</xsl:text>
</tracexsl:comment>
<tracexsl:text XML:space="preserve">
</tracexsl:text>
</xsl:template>

  為了展示這個新代碼,我將需要針對使用 mode 更改和 <xsl:call-template> 的樣式表來運行該代碼。不必為這個目的而編寫一個樣式表,我將借用 Xalan 所帶的某個一致性測試案例。它生成文本輸出,而不是 Html 或 XML,但它也足以顯示我的跟蹤工作正常。

  tracexsl2.xsl — 經過修訂的用於跟蹤樣式表的樣式表。

 tracexsl-sample2.xsl — 來自 Xalan 測試套件的 modes10.xsl 副本。

  當我使用 Xalan 對樣本運行 tracexsl2.xsl 時,我獲得了 tracexsl-sample2.xsl.withTrace 。

  tracexsl-sample2.XML — modes10.XML 的副本,它是測試案例的輸入文檔。

  當我使用 Xalan 對源文檔運行生成的 tracexsl-sample2.xsl.withTrace 時,它生成 tracexsl-sample2.XML.traceResult 。

  跟蹤輸出正變得有點冗長,是不是?這沒有關系 — 在本文的後面,我將討論如何裁減它。但現在我將更進一步地細化它,因為輸出中仍然沒有我認為重要的內容。

  但輸入是什麼?

  到目前為止,我已經生成大量關於調用什麼模板以及如何調用它們的信息。但是,當然,樣式表只是這個過程的一半;另一半是被樣式化的文檔。如果我不知道輸入來自哪裡,那麼很難理解為什麼我正在生成這一組特別的輸出。

  我可以采用 Xalan 在其自己的消息中所采用的方法,並顯示源文檔內的行號和列號。但標准的 XSLT 不能提供這一信息;我必須借助於 XSLT 擴展。由於如果不放棄可移植性,則無法使用它,因此我寧願不這樣做。

  此外,行和列確實不是描述 XML 文檔內的位置的最有意義的方式。顯示正在處理的節點的 XPath 將更實用:“/purchaSEOrder/customer/shippingAddress[2]”比“line 152,column 17”的信息更豐富。

 自動生成 XPath 事實上比您可能期望的更困難。當然,實際的路徑語法很簡單。但當 W3C 工作組(W3C Working Group)設計 XPath 語法時,他們決定使用 XML 名稱空間前綴這種方法,而沒有使用拼寫出完整的名稱空間 URI 的方法。遺憾的是,他們沒有為 聲明那些前綴提供任何語法,所以 XPath 自身沒有象它按道理來說的那麼有意義。我們已經把這方面的意見發送給了 XML 核心工作組(XML Core Working Group),請他們解決這一問題,因為這意味著沒有辦法編寫獨立於上下文的 XPath。

  另一個小問題是,可以在文檔的任何地方重新定義前綴……這樣,創建 XPath 的任何人必須准備創建新的前綴來消除這些沖突所帶來的歧義,並確保那些前綴不與正在使用中的任何其它前綴發生沖突。最簡單也是最不好看的辦法是, 總是在生成的 XPath 中生成新的前綴,而不是使用源文檔中的前綴 — 這對於程序來說,一點問題也沒有,但讀起來就比較困難。

  我已經決定避開這些問題,將就點,采用與 XPath 相似的對名稱空間不敏感的方法。跟蹤注釋主要為了讓我們閱讀,而不是讓實際的 XPath 處理器閱讀,而且重新定義前綴相對來說較少見,所以這種方法對目前而言足夠好了。在許多情況下,它事實上是完全可接受的節點的 XPath。我已經把生成這一點的代碼放入了它自己的模板中,所以當有更好的解決方案時,可以方便地替換它。

  這種簡化使得在 XSLT 中生成偽 XPath(Pseudo XPath)更容易。這個過程歸結為:

  依次檢查節點的所有祖先和節點本身

  檢查每個節點的類型

  輸出一個斜槓、節點的類型和名稱以及位置謂詞。

  位置號是必需的,以防節點有相同類型和名稱的兄弟節點,這樣可以表明我們引用的是哪個節點。出於這個目的, <xsl-number> 返回恰當的值 — 1 代表第一個這樣的實例,2 代表第二個,等等。

當用 <xsl:call-template> 調用下面這個模板,它將執行這個任務:

  清單 4. 在 XSLT 中的生成偽 XPath 的模板

<xsl:template name="pseudo-xpath-to-current-node">
<!-- Special-case for the root node, which otherwise
wouldn't generate any path at all. A bit of a kluge,
but it's simple and efficIEnt. -->
<xsl:if test="not(parent::node())">
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:for-each select="ancestor-or-self::node()">
<xsl:choose>
<xsl:when test="not(parent::node())">
<!-- This clause recognizes the root node, which doesn't need
to be explicitly represented in the XPath. -->
</xsl:when>
<xsl:when test="self::text()">
<xsl:text>/text()[</xsl:text>
<xsl:number level="single"/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="self::comment()">
<xsl:text>/comment()[</xsl:text>
<xsl:number level="single"/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="self::processing-instruction()">
<xsl:text>/processing-instruction()[</xsl:text>
<xsl:number level="single"/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="self::*">
<!-- This test for Elements works because the Principal
Node Type of the self:: axis happens to be Element.
-->
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:text>[</xsl:text>
<xsl:number level="single"/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="self::node()[name()='xmlns' | starts-with(name(),'XMLns:')]">
<!-- This recognizes namespace nodes, though it's a bit
ugly. XSLT 1.0 doesn't seem to have a more elegant
test. XSLT 2.0 is expected to deprecate the whole
concept of namespace nodes, so it may become a moot
point.
NS nodes are unique; a count isn't required. -->
<xsl:text>/namespace::</xsl:text>
<xsl:value-of select="local-name(.)"/>
</xsl:when>
<xsl:otherwise>
<!-- If I've reached this clause, the node must be an
attribute. Attributes are unique; a count is not
required. -->
<xsl:text>/@</xsl:text>
<xsl:value-of select="name(.)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>

我希望從我的注釋生成器代碼調用這個模板。這相當簡單 — 在 <tracexsl:comment> 內,我只需添加如下代碼:

<xsl:text> source=</xsl:text>
<tracexsl:call-template name="pseudo-xpath-to-current-node"/>

  現在我要必須做的是將 pseudo-xpath-to-current-node 模板放在注釋樣式表能找到的地方。我可以把該模板放入它自己的樣式表文件中,並使用 <xsl:include> 或 <xsl:import> 來包含它。但那將意味著,更改後的樣式表在沒有這個支持樣式表的情況下不能運行,我寧願采用這樣的解決方案:向受到這種困擾的客戶交付一個自包含的文件。

  所以我將利用已經修改樣式表這一事實,將這個模板復制到經過注釋的樣式表。為方便起見,我選擇將主副本存儲為我的用於樣式表的樣式表的一部分,從那裡復制它。在 XSLT 中,這非常方便,因為 document('') 使我能從當前正在執行的樣式表進行讀取。

  除了將 pseudo-xpath-to-current-node 模板添加到已修訂的 tracexsl3.xsl ,我還編寫了一個模板,它可以識別源樣式表中的頂層元素 <xsl:stylesheet> ,並在 <xsl:stylesheet> 的所有其它子元素之後,復制 pseudo-xpath-to-current-node 模板。為安全起見,我添加了一個測試,它首先檢查偽 XPath 模板是否已經存在 — 因為有時我可能想用 tracexsl 來調試它自己,而同一個模板有兩個副本將是一個錯誤。

  清單 5. 將 pseudo-xpath-to-current-node 復制到 <xsl:stylesheet> 的模板

<xsl:template match="xsl:stylesheet">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<xsl:if test="not(xsl:template[@name='pseudo-xpath-to-current-node'])">
<xsl:text>
</xsl:text>
<xsl:copy-of select="document('')/xsl:stylesheet/xsl:template[
@name='pseudo-xpath-to-current-node']"/>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:copy>
</xsl:template>

我把上述內容整理了一下,以下是我所獲得的:

  tracexsl3.xsl — 經過修訂的用於跟蹤樣式表的樣式表。

  tracexsl-sample3.xsl — 來自 Xalan 測試套件的 modes10.xsl 的副本。

  當我使用 Xalan 對樣本運行 tracexsl3.xsl 時,我得到了 tracexsl-sample3.xsl.withTrace

  tracexsl-sample3.XML — modes10.XML 的副本,它是測試案例的輸入文檔。

  當我使用 Xalan 對源文檔運行生成的 tracexsl-sample3.xsl.withTrace 時,它生成 tracexsl-sample3.XML.traceResult 。

  太多了!太多了!

  在上一節,我提到了使用 tracexsl.xsl 來調試自身的可能性。

  實際上,正如事實馬上會證明的,這種方法不是很好。我正在將注釋插入到每個模板的輸出中,還包括 pseudo-xpath-to-current-node 模板……這意味著我最終試圖在生成的注釋 中生成注釋。類似地,如果我為缺省模板生成一條注釋,那意味著在屬性之前輸出注釋,這是不允許的。事實證明,跟蹤將中斷我的跟蹤樣式表!

  (在本系列上一篇專欄文章的最後,我指出將注釋插入輸出並不總是安全的。這就是一個很好的示例。)

我確實可以將這些特定的模板作為特例來處理。但如果我正在跟蹤另一個具有同樣問題的樣式表,會怎麼樣呢?我所需要的是更一般的解決方案,它會讓用戶告訴 tracexsl.xsl :在 他們的模板中哪些在跟蹤時是安全的,哪些是不安全的。

  樣式表開發人員如何給我這種信息呢?一種簡單的解決方案是請他們向每個模板添加標記,表明該模板應該或不應該添加跟蹤代碼。(實際上,我或許應該采用缺省情況,這樣他們只需標記異常即可。)然後,我可以更改我的用於模板的模板以僅僅處理帶或者不帶標記的模板。

  什麼類型的標記?我建議采用屬性。允許 XSLT 元素帶有附加屬性,只要那些屬性位於其它名稱空間,這樣樣式表處理器知道自己可以忽略它們。我已經為 tracexsl: 前綴定義了名稱空間,所以我將使用這個名稱空間;它還可以幫助我記住這些屬性是我的跟蹤系統的命令。

  例如,我可能假定不應該向帶有 tracexsl:trace="no" 屬性的 <xsl-template> 元素添加跟蹤注釋生成器。要實現這一點,我將修改我的用於模板的模板的 match 條件,以在進一步處理之前檢查這個屬性,然後將這個標志添加到我所關心的這些模板。

  清單 6. 修改 match 條件,並標記不要跟蹤的模板

<xsl:template match="xsl:template[not(@tracexsl:trace='no')]>
...
</xsl:template>
<xsl:template match="@*|node()" priority="-1" tracexsl:trace="no">
...
</xsl:template>
<xsl:template name="pseudo-xpath-to-current-node" tracexsl:trace="no">
...
</xsl:template>


 

這就行了……但我願再作進一步討論。

  正如我已經指出的,每次處理器進入和離開模板,都會生成注釋,這可能產生數量多得驚人的信息,其中大多數信息可能與您正嘗試調試的問題無關。您可以用 tracexsl:trace="no" 以裁減信息,但是,接下來,每次想更改正在跟蹤什麼模板時,您必須修改樣式表來添加和除去這些屬性。

  更好的方法是,尋找一種方法來表明某個模板屬於我所感興趣的組,並指定在我運行 tracexsl.xsl 時應該跟蹤哪些組。我將通過擴展 tracexsl:trace 行為來做到這一點 — 現在“no”將是不被跟蹤的特殊組,但是,當這個值為 $tracegroups 變量的當前值的子串時,或者如果這個變量被設置成空字符串時,將跟蹤其它關鍵字。注:我必須檢查這個屬性實際上是否出現,因為當沒有這個屬性時, contains() 測試將返回 true(所有字符串都包含空字符串)。

  清單 7. 經過改進的 match ,以支持跟蹤組

<xsl:template match="xsl:template[not(@tracexsl:trace='no')
and ($tracegroups='' or
@tracexsl:trace and contains($tracegroups,@tracexsl:trace))]">

  這不是一個完美的測試 — 如果這個變量包含一列用逗號分隔的組“fred,ginger”,則它將匹配 tracexsl:trace 的值 "red" 。但就我的目的而言,它已經足夠好了,因為我可以隨意挑選互相不包含的組名。(如果您真的覺得這不方便,請隨意改進這個樣式表!)

  現在我所要做的是設置 $tracegroups 。我沒有強迫用戶去修改 tracexsl.xsl 以更改組,而是利用 stylesheet parameters ,這些是在開始樣式化處理之前可以由 XSLT 處理器設置的變量。為了接受該參數,我需要在我的 <xsl:stylesheet> 中添加另一條偽指令:


 

清單 8. 把 tracegroups 列表作為樣式表參數來接受

<xsl:param name="tracegroups" select="''"/>

  引號中的兩個字段表明,我將要接受名為 tracegroups 的參數,並且它的缺省值為空字符串。(必須要有兩層引號,因為 select 希望對 XPath 表達式求值,以獲取其值 — 內部的 '' 是空字符串的表達式,而它外面的 "" 引用這個表達式。)

  您實際上如何設置這個參數呢?將參數傳遞給樣式表的細節可以有多種,這取決於您正在使用的 XSLT 處理器以及您如何調用它。如果您正在使用 Xalan 的命令行工具,則可以按如下添加這個選項:

  對於 Xalan-J Process 或 Xalan-C testXSLT 驅動程序:-PARAM tracegroups "fred,ginger"

  對於 Xalan-C Xalan 驅動程序:-p tracegroups "fred,ginger"

  以要求僅向那些標記為屬於“ fred ”和“ ginger ”組的模板添加跟蹤。注:需要引號,那只是因為一些操作系統草率地將逗號解釋為命令行標記定界符。一種可替代的解決方案是用不會產生那種誤解的字符來分隔組名。

  如果您正在通過 TrAX (Javax.XML.transform) API 調用 XSLT 處理器,則通過發出對 Transformer 對象的 setParameter("tracegroups","fred,ginger") 調用,可以完成同樣的工作。如果您正在使用 Xalan-C,而不是 Xalan-J,則等價的調用是 XalanTransformer 對象上的 setStylesheetParam("tracegroups","fred,ginger") (請參閱 參考資料)。

當然,如果您正在使用其它處理器,可以查閱它的文檔,以了解關於它如何接受樣式表參數方面的細節。

  將上述內容合在一起,這裡就是一個完整的可供選擇的跟蹤樣式表。我已經作為示例向它添加了更多的 tracexsl:trace 屬性。請嘗試對其自身運行它!

  tracexsl4.xsl — 添加了 tracexsl:trace 和 tracegroups 支持的 TRACEXSL 樣式表。這個版本包括有關它如何工作的注釋,而且,我建議您將它實際保存下來以便重用。

  我將使用同一個 tracexsl4.xsl 的副本作為要跟蹤的樣本樣式表。

  tracexsl-sample4.xsl.withTrace — 添加了帶有跟蹤代碼的樣式表。注:沒有向 pseudo-xpath-to-current-node 模板添加跟蹤代碼,因為它有 tracexsl:trace="no" 。

  我將使用另一個完全相同的 tracexsl4.xsl 的副本作為注釋樣式表的輸入。

  tracexsl-sample4.traceResult 顯示(非常冗長的!)結果。

  我將再嘗試一次,但這次將 tracegroups 參數設置為“ stylesheet,template ”。這將只跟蹤屬於那些組的模板,具體地說,與 <xsl:stylesheet> 和 <xsl:template> 元素匹配的那些模板。

  tracexsl-sample4a.xsl.withTrace — 樣式表,所帶的跟蹤代碼僅添加到與 tracegroups 設置相匹配的模板中。注:跟蹤代碼仍不添加到偽 XPath 模板。

同樣,使用同一個 tracexsl4.xsl 副本作為這個帶有選擇性注釋的樣式表的輸入。我准備在 不設置 tracegroups 的情形下,運行一遍。

  tracexsl-sample4a.traceResult顯示結果 — 現在沒有那麼多瑣碎的內容,因為沒有跟蹤同一個模板。正如您所見,這個受限的跟蹤使得 更容易理解實際所發生的事情。

  家庭作業:如果我第二遍又指定 tracegroups ,您能猜出將發生什麼嗎?請嘗試一下!

  更進一步的討論

  既然您了解了如何樣式化樣式表,那麼您可以將這些同樣的技術應用到其它自動化增強中。例如,可以編寫能生成 <xsl:message> 調用而不是注釋的樣式表 — 也許可以利用 Uche Ogbui 以前在 developerWorks 上描述過的技術(請參閱 參考資料)。

  您也可以用更復雜的機制來替代簡單的 tracegroups 機制。一種令人感興趣的可能性是傳遞 XPath,我們要用這個 XPath 來測試是否應該跟蹤模板,並調用 EXSLT Dynamic XPath Evaluation 擴展( dyn:evaluate() )來執行它。盡管並不是所有的 XSLT 處理器都支持 EXSLT 庫,但至少它已進行了足夠的標准化,如果 出現EXSLT 庫,則它的行為是可以預測的。

  您可能還想做一點其它清理工作。使 <xsl:namespace-alias> 方法略顯繁瑣的原因之一是,用於別名式前綴的名稱空間聲明往往出現在使用該前綴的地方 — 這意味著它們遍布整個文檔。最好在文件頂部用生成的 <xsl:stylesheet> 偽指令聲明前綴一次。在 XSLT 1.0 中,這相當不好看;顯式創建名稱空間節點的唯一方式是創建一個使用該名稱空間節點的臨時元素,並從那兒抽取該名稱空間節點。

清單 9. 為了創建名稱空間節點而創建臨時元素

<xsl:variable name="dummy">
<xsl:element name="tracexsl:x" namespace="http://www.my.Net/my markup"/>
</xsl:variable>
<xsl:copy-of select="xx:node-set($dummy)//namespace::*"/>

  (預計 XSLT 2.0 將引入新的偽指令 <xsl:namespace> ,這將是完美的解決方案。)

  正如我在前面啟動該項目時所說的,您還可以轉換到使用 <xsl:element> 而不是使用 <xsl:namespace-alias> 來顯式地生成帶有標准的 xsl: 前綴的新的樣式表元素。這樣做可能使跟蹤工具稍微更難以編寫和維護,這還將意味著您可能不再看到哪些偽指令是由這個跟蹤工具生成的,但獲得更干淨的輸出可能值得付出這些代價。

  一些用戶可能想分析跟蹤信息,可能對調用每個模板的頻率進行計數。顯然,您可以編寫樣式表來掃描整個跟蹤輸出,查找注釋以及對它們進行排序和計數。如果您主要對這些感興趣,那麼您可能想改變注釋的內容 — 或者甚至可能將它們完全改變成其它類型的注釋 — 使分析器更易於處理它們。但如果您不需要可移植的解決方案,那麼作為 Xalan TraceListener 這種衡量手段可能更容易編寫。

  正如我所提到的,生成完全正確的 XPath(不是近似的偽 XPath)將花費更多功夫。除名稱空間問題之外,請注意,我在這裡所顯示的版本並不表明它來自哪個源文檔 — 如果您的樣式表使用 document() 函數或其它輔助的源樹,那麼這就很重要。我確信會有一些辦法來解決這些問題,但我把它們作為練習留給讀者。

  當然,跟蹤只是樣式化樣式表的一個示例。更一般的情況,這項技術還給您另一種方法來實現對 XSLT 語言的擴展。正如您在我創建 tracexsl:trace 屬性時所見,您可以創造新的樣式表修飾符 — 或全新的偽指令 — 您的用於樣式表的樣式表將其轉換成詳細的 XSLT 操作,以實現預期的效果。如果您仔細地避免了特定於處理器的特性,則您可以使這些解決方案用於任何 XSLT 處理器。

  我相信您會考慮我沒有設想到的應用程序。要認識到的全部內容是,XSLT 不僅僅是一個用於生成良好顯示和打印輸出的工具 — 它是一個非常通用的文檔處理器。由於樣式表本身是可以被預處理的文檔……從某種意義上講,編譯器就是一個非常奇妙的預處理器。

  由於 XSLT 本身是一個 XML 應用程序,因此一切都是可能的。難道常規用途的基於標准的工具不好嗎? <grin/> !


 




 

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