1

是否可以在 XSLT 中进行“预处理”?

通过预处理,我的意思是更新源树的(内存表示)。

这可能吗,还是我需要为它做多次转换。

用例:我们为客户提供 Docbook 参考手册,但对于某些客户,这些需要不同的“皮肤”(不同的图像等)。所以我希望做的是根据参数转换图像文件引用路径。然后应用其余的普通 Docbook XSL 模板。

4

4 回答 4

3

扩展埃蒙的答案......

对于 XSLT 1.0 或 2.0,首先将中间(预处理)结果放入 <xsl:variable> 元素中,该元素可以全局(顶级)或本地(在模板内)声明。

<xsl:variable name="intermediate-result">
  <!-- code to create pre-processed result, e.g.: -->
  <xsl:apply-templates mode="pre-process"/>
</xsl:variable>

在 XSLT 2.0 中,$intermediate-result 变量的值是由一个文档节点(在 XSLT/XPath 1.0 中称为“根节点”)组成的节点序列。您可以像访问任何其他变量一样访问和使用它,例如,select="$intermediate-result/doc"

但是在 XSLT 1.0 中,$intermediate-result 变量的值不是一流的节点集。相反,它是一种称为“结果树片段”的东西。它的行为就像一个包含一个根节点的节点集,但是您在如何使用它方面受到限制。您可以复制它并获取它的字符串值,但不能使用 XPath 进行深入研究,如 select="$intermediate-result/doc"。为此,您必须首先使用处理器的 node-set() 扩展函数将其转换为一流的节点集。在 Saxon 6.5、libxslt 和 4xslt 中,您可以使用 exsl:node-set() (如 Eamon 的回答)。在 MSXML 中,您需要使用 msxsl:node-set(),其中 xmlns:msxsl="urn:schemas-microsoft-com:xslt",在 Xalan 中,我相信它称为 xalan:nodeset()(没有连字符,但您必须使用 Google 搜索命名空间 URI)。

XSLT 2.0 简单地取消了结果树片段,使得 node-set() 变得不必要了。

于 2009-12-07T21:21:54.623 回答
1

这对于符合标准的 XSLT 1.0 是不可能的。但是,在我使用的每个实际实现中都是可能的。但是,执行此操作的扩展因引擎而异。在标准 XSLT 2.0 中也是可能的(无论如何,它更容易使用 - 所以如果可以,就使用它)。

如果您的 xslt 处理器支持EXSLT,则exsl:node-set()函数可以满足您的需求。msxml 也有一个同名的扩展函数(但使用不同的命名空间 uri,不幸的是,这些函数并不是完全兼容的)。

于 2009-12-07T13:06:30.880 回答
1

由于您正试图从同一个 DocBook XML 源生成稍微不同的输出,因此您可能希望查看 DocBook XSL 样式表中的“分析”(条件标记)支持。请参阅DocBook XSL中的第 26 章: Bob Stayton 的完整指南:

Profiling 是 DocBook 中用来描述条件文本的术语。条件文本意味着您可以创建一个带有一些标记为条件元素的 XML 文档。当您处理此类文档时,您可以指定哪些条件适用于该版本的输出,并且样式表将包含或排除标记的文本以满足条件。当您需要生成多个版本的文档并且版本略有不同时,此功能很有用。

例如,要为同一文档的 Windows 和 Mac 版本使用不同的图像,您可能有一个像这样的 DocBook XML 片段:

<figure>
  <title>The Foo dialog</title>
  <mediaobject>
    <imageobject os="windows">
      <imagedata fileref="screenshots/windows/foo.png"/>
    </imageobject>
    <imageobject os="mac">
      <imagedata fileref="screenshots/mac/foo.png"/>
    </imageobject>
  </mediaobject>
</figure>

然后,您将使用profile.os参数设置为windowsor的 DocBook XSL 样式表的启用分析版本mac

于 2009-12-08T06:16:37.537 回答
0

也许您应该在这里使用 XSLT“OOP”方法。将所有客户端的所有通用模板放在样式表中,并为每个客户端创建一个样式表,其中特定模板覆盖通用模板。使用 xsl:import 导入特定样式表中的通用样式表,调用客户端对应的样式表只进行一次处理。

于 2009-12-08T09:09:54.903 回答