跳转到内容

XSLTForms/转换函数

来自 Wikibooks,开放世界中的开放书籍

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 样式表,则为 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>

显示 XML 源代码

[编辑 | 编辑源代码]

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%">&lt;svg xmlns="http://www.w3.org/2000/svg" 
           xmlns:svg="http://www.w3.org/2000/svg" 
           width="900" 
           height="1000"&gt;
  &lt;desc&gt;SVG representation of the data&lt;/desc&gt;
  ...
  &lt;/svg&gt;</svg>

解决此问题的一种方法是使用实验性动作 xf:setnode 以及 innerouter 属性,以替换节点的内容或节点本身。

  <xf:trigger>
    <xf:label>Inner</xf:label>
    <xf:setnode ref="." ev:event="DOMActivate"
               inner="'&lt;item&gt;b&lt;/item&gt;'"/>
  </xf:trigger>
  <xf:trigger>
    <xf:label>Outer</xf:label>
    <xf:setnode ref="item" ev:event="DOMActivate"
               outer="'&lt;item&gt;c&lt;/item&gt;'"/>
  </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() 测试用例 中收集到一些进一步的信息,这些测试用例说明了调用函数的各种不同方法,并显示了在每种情况下它产生的结果。

华夏公益教科书