XSLT 的第一個版本有很大的局限性,只能有一個輸入和一個輸出(雖然可以有多個模板文件)。該標准的第 2 版仍然要求一個輸入,但是輸出系統更加靈活了。現在可以使用 xsl:result-document 指令產生多個輸出文件。這一新的標簽有兩個重要屬性,如表 1 所示。
表 1. xsl:result-document 屬性
屬性 說明 href 輸出文件的文件名或者完全限定的 URL format 使用的格式名,如對應 xsl:output 指令中所定義的為了試驗該指令,我設計了一個輸入 XML 文件,包括一組測試結果(參見清單 1)。
清單 1. 輸入 XML 文件
<?XML version="1.0" encoding="UTF-8"?>
<tests>
<testrun run="test1">
<test name="foo" pass="true" />
<test name="bar" pass="true" />
<test name="baz" pass="true" />
</testrun>
<testrun run="test2">
<test name="foo" pass="true" />
<test name="bar" pass="false" />
<test name="baz" pass="false" />
</testrun>
<testrun run="test3">
<test name="foo" pass="false" />
<test name="bar" pass="true" />
<test name="baz" pass="false" />
</testrun>
</tests>
這段 XML 非常簡單。每個測試運行中都有一組帶有 pass 標記的指定測試,用以說明測試是否成功。
為每個測試創建一個文件
首先為每個測試結果創建一個文件,XSL 模板如清單 2 所示。
清單 2. 為每個測試創建文件的代碼
<?XML version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
XMLns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:output method="html" indent="yes" name="Html"/>
<xsl:template match="/">
<xsl:for-each select="//testrun">
<xsl:variable name="filename"
select="concat('output1/',@run,'.Html')" />
<xsl:value-of select="$filename" /> <!-- Creating -->
<xsl:result-document href="{$filename}" format="Html">
<Html><body>
<xsl:value-of select="@run"/>
</body></Html>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
有幾個地方值得注意,從文件頭開始說起。stylesheet 標簽的 version 屬性被設為 2.0,這樣就能夠使用 xsl:result-document 標簽了。接下來,樣式表本身設置 text 作為輸出類型。這意味著如果希望讓這個文件具有 HTML 格式,那麼還需要定義類型 Html 的第二個指定格式。我在 xsl:result-document 標簽中使用這種格式。
然後使用 xsl:for-each 循環遍歷 testrun 標簽。在每個標簽中使用 variable 標簽創建一個新的 $filename 變量,將輸出目錄名(output1)、 運行名和擴展名 .Html 合成一個路徑。
然後我使用 value-of 標簽和 $filename 變量告訴用戶正在創建的文件。再用 xsl:result-document 標簽打開新文檔輸出 Html。清單 3 顯示了運行上述數據文件時的結果。
清單 3. 運行示例數據文件的結果(使用 Saxon)
Creating output1/test1.Html
Creating output1/test2.Html
Creating output1/test3.Html
獲得更好的結果
xsl:result-document 標簽的內容按照與模板其他部分相同的方式計算似乎有點不可思議,但確實如此。模板上下文中的所有變量都可以使用。
作為一個例子,我修改了 xsl:result-document 標簽中的代碼,以便提供關於測試結果的更多信息(參見清單 4)。
清單 4. 更好的 Html 輸出
<xsl:result-document href="{$filename}" format="Html">
<Html><head>
<title>Test results - <xsl:value-of select="@run"/></title>
</head><body>
<xsl:value-of select="@run"/> <!-- Run -->
<table>
<tr><td>Test</td><td>Pass</td></tr>
<xsl:for-each select="test">
<tr><td>
<xsl:value-of select="@name" />
</td><td>
<xsl:value-of select="@pass" />
</td></tr>
</xsl:for-each>
</table>
</body></Html>
</xsl:result-document>
輸出結果如清單 5 所示。
清單 5. 改進的 Html 輸出結果
<Html>
<head>
<meta http-equiv="Content-Type"
content="text/Html; charset=UTF-8">
<title>Test results - test1</title>
</head>
<body>
<!-- Run: test1-->
<table>
<tr>
<td>Test</td>
<td>Pass</td>
</tr>
<tr>
<td>foo</td>
<td>true</td>
</tr>
<tr>
<td>bar</td>
<td>true</td>
</tr>
<tr>
<td>baz</td>
<td>true</td>
</tr>
</table>
</body>
</Html>
創建索引
最後還需要增加一個索引文件指向輸出的所有測試結果。為此,我使用了另一個 xsl:result-document 標簽,並將輸出硬編碼到索引文件中(參見清單 6)。
清單 6. 創建索引文件的代碼
<!-- Creating the index -->
<xsl:result-document href="output3/index.Html"
format="Html">
<Html><head><title>Test Index</title></head>
<body>
<xsl:for-each select="//testrun">
<a href="{@run}.Html"><xsl:value-of select="@run" />
</a><br/>
</xsl:for-each>
</body>
</Html>
</xsl:result-document>
這一段放在為每個測試案例建立 Html 文件的 xsl:for-each 循環之後。清單 7 顯示了得到的索引文件。
清單 7. 索引文件
<Html>
<head>
<meta http-equiv="Content-Type"
content="text/Html; charset=UTF-8">
<title>Test Index</title>
</head>
<body><a href="test1.Html">test1</a><br>
<a href="test2.Html">test2</a><br>
<a href="test3.Html">test3</a><br></body>
</Html>
結束語
使用 xsl:result-document 指令可以將一個 XSL 模板從單個數據源輸出到多個文件中。這種功能在 XSLT 1.x 屬於非標准擴展,為 XSLT 模板創造者打開了新的機會之窗。