XSLTForms/轉換函式
transform() 函式是 XSLTForms 對標準 XForms 函式庫的擴充套件。公開討論表明它是基於對 類似函式 的提議,該函式將被包含在 XForms 2.0 中,但工作似乎在 2011 年陷入停滯。在 XPath 表示式模組 的當前草案中似乎沒有 transform() 函式,目前也沒有為 transform() 函式單獨模組的活動規範。
transform() 函式將外部 XSLT 樣式表應用於節點集。在當前版本的 XSLTForms(大約從 2014 年開始)中,它接受三個或更多引數。
- 第一個引數是要轉換的節點(例如
instance('foo')/bar/baz或只是child-element或.)。 - 第二個引數要麼是
- 作為字串的 XSLT 樣式表的 URI(例如
'my-transform.xsl'),要麼是 - XSLT 樣式表的字串表示。
- 作為字串的 XSLT 樣式表的 URI(例如
- 第三個引數如果是字串形式的 XSLT 樣式表,則為
true,如果是 XSLT 樣式表的 URI,則為false。 - 如果存在,第四、六、八... 個引數是 XSLT 樣式表引數的名稱。
- 如果存在,第五、七、九... 個引數是這些引數的值。
注意:早期版本的函式只接受兩個引數:要轉換的節點和 XSLT 樣式表的 URI。
transform() 函式返回一個字串。這對許多 XSLT 使用者來說似乎不太可能,因此需要強調:transform() 函式返回一個字串。
- 如果 XSLT 輸出方法是
text,則返回值是字串(在幾乎所有瀏覽器中,在幾乎所有情況下,都包裝在某種瀏覽器相關的 XML 元素中)。 - 如果 XSLT 輸出方法是
xml,則返回值是生成的 XML 文件的序列化形式。在大多數情況下,檢視它將顯示尖括號和與號作為<和&進行轉義。但是,如果返回值被注入到 XHTML 文件中,則結果將像普通的 HTML 一樣格式化。
(那麼 html 輸出方法呢?)
transform() 的一個用途是將 XML 例項資料格式化為適當地格式化的 HTML,以便瀏覽器以方便的只讀方式顯示。例如
<div style="margin: 1em 0;">
<xf:output value="transform(my-tricky-element, 'display-tricky.xsl')"
mediatype="application/xhtml+xml" />
</div>
transform() 的另一個用途是美化 XML 例項資料,以便瀏覽器以方便的只讀方式顯示 XML 原始碼。例如
<h2>XML representation of the data</h2>
<pre style="border: 2px #552211 solid;
padding: 0.5em;
background-color: #f7eed4;">
<xf:output value="transform(instance('doc'),'../lib/prettyprint.xsl')"
mediatype="text/plain" />
</pre>
此示例假設一個美化樣式表,該樣式表會生成帶有換行符和適當縮排的輸出。這在原則上不是必需的(可以使用 serialize(instance('user-data')) 代替),但在實踐中很有用,因為否則一些瀏覽器會在一行很長的輸出中顯示整個 XML 文件。
由於 transform() 返回一個字串,因此以下嘗試為 XForms 生成新的文件例項以便進一步處理將失敗:它不會用轉換的輸出替換例項 foo,而是用轉換結果的序列化字串形式替換 foo 的內容。
<xf:trigger>
<xf:label>Generate diagram</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('svg')"
value="transform(instance('input'),'make-svg.xsl')"/>
<xf:toggle case="picture"/>
</xf:action>
</xf:trigger>
如果 svg 例項最初包含一個正常的 SVG 文件,那麼在觸發顯示的觸發器後,它將包含一個 SVG 元素,該元素包含 XML 轉義的 SVG 文件作為一個單獨的文字節點。
<svg xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"><svg xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
width="900"
height="1000">
<desc>SVG representation of the data</desc>
...
</svg></svg>
解決此問題的一種方法是使用實驗性動作 xf:setnode 以及 inner 或 outer 屬性,以替換節點的內容或節點本身。
<xf:trigger>
<xf:label>Inner</xf:label>
<xf:setnode ref="." ev:event="DOMActivate"
inner="'<item>b</item>'"/>
</xf:trigger>
<xf:trigger>
<xf:label>Outer</xf:label>
<xf:setnode ref="item" ev:event="DOMActivate"
outer="'<item>c</item>'"/>
</xf:trigger>
另一種解決方法是將字串提交到伺服器上的指令碼,該指令碼將它作為 XML 回顯。(參見 關於 setnode 操作的討論 中的示例)。
在 Safari 中,以及在較舊版本的 Chrome 中(直到版本 30,甚至可能更晚),如果在 transform() 的第二個引數中給出的樣式表包含 xsl:import 指令,則轉換可能會失敗。症狀是一個錯誤警報,提示 TypeError: null is not an object (evaluating 'resultDocument.documentElement')。(如果樣式表包含 xsl:include 指令,則也可能會出現此問題,但尚未得到驗證。)此問題不會出現在 Firefox、Opera 或更新版本的 Chrome 中(從版本 49 開始,甚至可能更早)。
解決方法:刪除 xsl:import,以便樣式表成為一個獨立的物件,不依賴於其他樣式表。
可以從 一組 transform() 測試用例 中收集到一些進一步的資訊,這些測試用例說明了呼叫函式的各種不同方法,並顯示了在每種情況下它產生的結果。