使用 XSLT 轉換 XML

內容與呈現的分離是 XML 的一個關鍵設計特點。XML 文件的結構旨在反映和闡明內容自身各個方面之間的重要關係,不受需要提供任何關於資料最終如何呈現的指示的阻礙。隨著越來越多的資料傳輸自動化並在透過網路連線的高度異構機器之間進行,這種智慧結構變得尤為重要。

然而,最終儲存在 XML 文件中的大部分內容都需要呈現給人類讀者。由於瀏覽器提供了熟悉且高度靈活的介面,它是交付此類 XML 內容呈現版本的理想機制。Firefox 從零開始,利用各種 XML 技術構建,自身集成了處理原始 XML 文件和用於樣式化及佈局以供 HTML 顯示的專用樣式表所需的所有機制,透過客戶端處理減少了伺服器負載。

目前,Gecko(Firefox 背後的佈局引擎)支援兩種形式的 XML 樣式表。對於外觀的基本控制——字型、顏色、位置等——Gecko 使用 CSS

我們在此關注 Gecko 支援的第二種樣式表:XSLT 樣式表。XSLT 代表“可擴充套件樣式表語言/轉換”(eXtensible Stylesheet Language/Transform),這個名稱非常貼切。XSLT 允許樣式表作者以兩種重要方式轉換主 XML 文件:操作和排序內容,如果需要,甚至可以進行整體重排序;以及將內容轉換為不同的格式(在 Firefox 的情況下,重點是在執行時將其轉換為 HTML,然後瀏覽器可以顯示它)。

什麼是 XSLT?

可擴充套件樣式表語言/轉換(eXtensible Stylesheet Language/Transform)是一種非常強大的語言,對其進行完整討論超出了本文的範圍,但對一些基本概念的簡要討論將有助於理解後續的 Netscape 功能描述。

XSLT 樣式表是一個 XML 文件。與 CSS 有其自己的專用語法不同,XSLT 樣式表是一個 XML 文件,必須符合所有 XML 規則,包括格式良好性。因此,轉換的模型是使用一個 XML 文件來轉換另一個 XML 文件。

XSLT 樣式表透過包含標準 XSLT 標題來標記。XSLT 樣式表中最外層的元素必須是 <xsl:stylesheet> 元素(一個可接受的替代方案是 <xsl:transform> 元素)。此元素將至少包含一個名稱空間宣告和強制的版本屬性。也可以包含其他名稱空間和三個可選屬性。

XSLT 名稱空間

XSLT 的強制名稱空間是 "http://www.w3.org/1999/XSL/Transform"。名稱空間在 XML 中引起了相當多的困惑。儘管名稱空間看起來常常是 URI,但它們實際上並不引用該地址處的資源。相反,它們是一種為已知元素集指定唯一識別符號的方式。字串 "http://www.w3.org/1999/XSL/Transform" 是一個常量,它指定那些被標記的元素屬於 W3C 在 1999 年 XSLT 推薦標準中指定的標籤集。樣式表中偶爾出現的另一個字串 "http://www.w3.org/TR/WD-xsl" 表示符合 W3C 文件的早期工作草案(因此有 WD)。後一個名稱空間與 W3C 最終採用的名稱空間不相容,並且不受 Netscape 支援。

由於重複鍵入 "http://www.w3.org/1999/XSL/Transform" 會很繁瑣並導致標記難以閱讀,因此有一種標準機制可以在樣式表標題中為名稱空間分配一個簡寫名稱。因此,開放樣式表元素的完整示例可能如下所示。

xml
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

xmlns 偽屬性將簡寫名稱 xsl 對映到整個名稱空間,以便在後續文件中使用。因此,上面的樣式表元素字首為 xsl:。儘管 xsl 是約定俗成的簡寫名稱(稱為字首),但它並非強制性,並且完全可以選擇不同的名稱。本文中的示例都假設使用 xsl 字首。

XSLT 如何處理 XML 樹

XSLT 轉換引擎(稱為處理器)不直接作用於文件。在轉換髮生之前,主 XML 文件和樣式表文檔必須經過解析器處理,解析器會在記憶體中建立文件結構的抽象表示。這種表示被稱為樹,是處理器實際操作的物件。樹是一種抽象資料型別,一個概念模型,可以根據解析器和處理器以各種方式實現。Netscape 使用類似於 W3C DOM 的結構作為其樹結構,但其他結構也是可能的。唯一的要求涉及樹中物件的佈局、它們的屬性及其關係。

這棵樹由節點的分層框架組成。它可以由七種不同型別的節點構成:單個根節點、元素節點、文字節點、屬性節點、註釋節點、處理指令節點和名稱空間節點。

樹的頂部是根節點。根節點不對應於 XML 文件的任何單個部分:它代表整個文件。根節點下方是其子節點,可以是元素、註釋、處理指令等。其中一些子節點也可能有子節點。這可以持續多個層級。關於哪些型別的節點可以出現在哪裡存在某些限制:例如,文字節點不能有子節點。

處理器動作的結果也是一棵樹。Netscape 使用這棵樹在瀏覽器視窗中渲染內容。

XPath 和節點選擇

本質上,XSLT 樣式表是一組規則,稱為模板,它們宣告任何匹配此特定模式的節點都應以這種特定方式操作,並最終位於結果樹中的這個特定位置。如何實現這一點則由處理器決定。由於樣式表的執行順序無法保證,XSLT 不支援任何產生副作用的功能。在這方面,它類似於 Lisp 或 Scheme。

轉換取決於處理器能夠在樹上精確定位單個節點。為了方便這一點,W3C 決定使用一種單獨的語言 XPath,它在 XSLT 上下文之外也有用途。顧名思義,XPath 定義了處理器必須遍歷樹以到達所需節點的“路徑”。這條路徑由待評估的 XPath 特定表示式組成,這些表示式可能包含多個要匹配的條件、關聯節點的方式以及/或指示樹內的方向性。XPath 最常用於 XSLT 的部分的更完整描述見參考部分。

模板匹配中潛在的衝突透過使用一組級聯的優先順序規則來解決。一般來說,更具體的模板規則優先於不那麼具體的模板規則,並且,在其他條件相同的情況下,文件中稍後出現的模板規則優先於早期出現的模板規則。

樣式表可以透過處理指令附加到 XML 文件。要指示應使用哪個 XSLT 樣式表來處理特定的 XML 文件,請在 XML 文件本身中包含處理指令。例如,如果樣式表名為 inventory.xsl 並且與 XML 文件位於同一目錄中,則 XML 文件中的處理指令將如下所示

xml
<?xml-stylesheet type="text/xml" href="inventory.xsl"?>

這必須放在 XML 文件的序言部分。

基本示例

第一個例子演示了在瀏覽器中設定 XSLT 轉換的基礎知識。該例子接受一個包含文章資訊(標題、作者列表和正文)的 XML 文件,並將其以人類可讀的形式呈現出來。

XML 文件 (example.xml) 如下所示。

xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="example.xsl"?>
<Article>
  <Title>My Article</Title>
  <Authors>
    <Author>Mr. Foo</Author>
    <Author>Mr. Bar</Author>
  </Authors>
  <Body>This is my article text.</Body>
</Article>

XML 檔案中的 ?xml-stylesheet 處理指令透過其 href 屬性指定要應用的 XSLT 樣式表。

此 XSL 樣式表文件 (example.xsl) 如下所示

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="/">
    Article - <xsl:value-of select="/Article/Title"/>
    Authors: <xsl:apply-templates select="/Article/Authors/Author"/>
  </xsl:template>

  <xsl:template match="Author">
    - <xsl:value-of select="." />
  </xsl:template>

</xsl:stylesheet>

XSLT 樣式表以 xsl:stylesheet 元素開頭,該元素包含用於建立最終輸出的所有模板。上面的示例有兩個模板——一個匹配根節點,一個匹配 Author 節點。匹配根節點的模板輸出文章標題,然後透過 apply-templates 處理所有匹配 Authors 節點子級的 Author 節點的模板。

嘗試示例

  1. 在檔案系統中建立一個目錄,並在其中建立上面列出的 example.xmlexample.xsl 檔案

  2. 在該目錄中啟動本地伺服器,其中包含這些檔案。這允許您像這些檔案託管在網際網路上一樣瀏覽目錄中的檔案。

    警告: 直接從檔案系統開啟 XML 檔案將不起作用,因為從檔案系統載入樣式表是 跨源請求,預設情況下將被禁止。將 XML 和樣式表託管在同一個本地伺服器上可確保它們具有相同的源。

  3. 從瀏覽器開啟 example.xml

  4. 瀏覽器輸出如下所示

    Browser Output :
    
        Article - My Article
        Authors:
        - Mr. Foo
        - Mr. Bar
    

生成 HTML

XSLT 在瀏覽器中的一個常見應用是將 XML 在客戶端轉換為 HTML。此示例將把包含文章資訊的輸入文件 (example2.xml) 轉換為 HTML 文件。

文章的 <body> 元素現在包含 HTML 元素(<b><u> 標籤)。XML 文件同時包含 HTML 元素和 XML 元素,但只需要一個名稱空間,即 XML 元素的名稱空間。由於沒有 HTML 名稱空間,並且使用 XHTML 名稱空間會迫使 XSL 建立一個行為不像 HTML 文件的 XML 文件,因此 XSL 樣式表中的 xsl:output 將確保結果文件被視為 HTML。對於 XML 元素,我們需要自己的名稱空間 http://devedge.netscape.com/2002/de,併為其指定字首 myNS (xmlns:myNS="http://devedge.netscape.com/2002/de")

XML 檔案

xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="example2.xsl"?>
  <myNS:Article xmlns:myNS="http://devedge.netscape.com/2002/de">
    <myNS:Title>My Article</myNS:Title>
    <myNS:Authors>
      <myNS:Author company="Foopy Corp.">Mr. Foo</myNS:Author>
      <myNS:Author>Mr. Bar</myNS:Author>
    </myNS:Authors>
    <myNS:Body>
      The <b>rain</b> in <u>Spain</u> stays mainly in the plains.
    </myNS:Body>
  </myNS:Article>

使用的 XSL 樣式表需要有兩個名稱空間——一個用於 XSLT 元素,一個用於 XML 文件中我們自己的 XML 元素。透過使用 xsl:output 元素,XSL 樣式表的輸出被設定為 HTML。透過將輸出設定為 HTML 並且結果元素(藍色著色)沒有名稱空間,這些元素將被視為 HTML 元素。

帶有 2 個名稱空間的 XSL 樣式表

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:myNS="http://devedge.netscape.com/2002/de">

  <xsl:output method="html"/>
  …
</xsl:stylesheet version="1.0">

建立了一個匹配 XML 文件根節點的模板,並用於建立 HTML 頁面的基本結構。

建立基本的 HTML 文件

xml
…
<xsl:template match="/">
<html>

  <head>

    <title>
      <xsl:value-of select="/myNS:Article/myNS:Title"/>
    </title>

    <style>
      .myBox {margin:10px 155px 0 50px; border: 1px dotted #639ACE; padding:0 5px 0 5px;}
    </style>

  </head>

  <body>
    <p class="myBox">
      <span class="title">
        <xsl:value-of select="/myNS:Article/myNS:Title"/>
      </span> </br>

      Authors:   <br />
        <xsl:apply-templates select="/myNS:Article/myNS:Authors/myNS:Author"/>
    </p>

    <p class="myBox">
      <xsl:apply-templates select="//myNS:Body"/>
    </p>

  </body>

</html>
</xsl:template>
…

還需要三個 xsl:template 來完成示例。第一個 xsl:template 用於作者節點,第二個處理正文節點。第三個模板有一個通用匹配規則,將匹配任何節點和任何屬性。它需要用於保留 XML 文件中的 HTML 元素,因為它匹配所有這些元素並將它們複製到轉換建立的 HTML 文件中。

最後 3 個模板

xml
…
<xsl:template match="myNS:Author">
    --   <xsl:value-of select="." />

  <xsl:if test="@company">
    ::   <b>  <xsl:value-of select="@company" />  </b>
  </xsl:if>

  <br />
</xsl:template>
xml
<xsl:template match="myNS:Body">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
…

最終的 XSLT 樣式表如下所示

最終的 XSLT 樣式表

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:myNS="http://devedge.netscape.com/2002/de">

  <xsl:output method="html" />

  <xsl:template match="/">
    <html>

      <head>

        <title>
          <xsl:value-of select="/myNS:Article/myNS:Title"/>
        </title>

        <style>
          .myBox {margin:10px 155px 0 50px; border: 1px dotted #639ACE; padding:0 5px 0 5px;}
        </style>

      </head>

      <body>
        <p class="myBox">
          <span class="title">
            <xsl:value-of select="/myNS:Article/myNS:Title"/>
          </span> <br />

          Authors:   <br />
            <xsl:apply-templates select="/myNS:Article/myNS:Authors/myNS:Author"/>
          </p>

        <p class="myBox">
          <xsl:apply-templates select="//myNS:Body"/>
        </p>

      </body>

    </html>
  </xsl:template>

  <xsl:template match="myNS:Author">
      --   <xsl:value-of select="." />

    <xsl:if test="@company">
      ::   <b>  <xsl:value-of select="@company" />  </b>
    </xsl:if>

    <br />
  </xsl:template>

  <xsl:template match="myNS:Body">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

XSLT/XPath 參考

進一步閱讀

書籍

  • XSLT:程式設計師參考,第二版
    • 作者:Michael H. Kay
    • 頁數:992 頁
    • 出版商:Wrox;第二版 (2001 年 5 月 3 日)
    • ISBN: 0764543814
      • Michael Kay 是 W3C XSL 工作組成員,也是他自己的開源 XSLT 處理器 Saxon 的開發者。他也是唯一一本達到第二版的關於該主題的書的作者。這是一本非常大、排版精良且詳盡(有時甚至令人筋疲力盡)的書,涵蓋了 XSLT 故事中的每一個可能的基礎。

https://www.amazon.com/XSLT-Programmers-Reference-Programmer/dp/0764543814

  • XSLT
    • 作者:Doug Tidwell
    • 頁數:473 頁
    • 出版商:O'Reilly Media;第一版 (2001 年 8 月 15 日)
    • ISBN: 0596000537
      • Doug Tidwell 是 IBM 的高階開發人員,也是 XML 技術領域的重要倡導者。他在 IBM 龐大的 XML 開發人員網站上撰寫了多篇關於 XML 各個方面的文章和教程。這本書的全面性略遜於 Michael Kay 的著作,但它很好地涵蓋了基礎知識,並提供了一些引人入勝的示例。

https://www.amazon.com/Xslt-Doug-Tidwell/dp/0596000537

  • 學習 XML,第二版
    • 作者:Erik T. Ray
    • 頁數:432 頁
    • 出版商:O'Reilly Media;第二版 (2003 年 9 月 22 日)
    • ISBN: 0596004206
      • 正如標題所示,這是對 XML 的一般性概述。第 6 章專門討論 XSLT。

https://www.amazon.com/gp/product/0596004206

規範

文章

教程/示例