我有一个现有的XSLT样式表,它采用XML并生成格式良好的XHTML。我想制作这个样式表的XSL-FO版本,通过Apache FOP生成PDF。我想知道的是:
有没有方便使用xslt模式我需要学习做以下事情:
我知道我可以使用
创建新节点<xsl:element>
但我还需要其他有用的东西吗?请注意,虽然我没有从一种XSLT格式复制到另一种格式,但我已经完成了TONS of XML-&gt; XHTML通过XSLT,所以我熟悉该语言的大部分核心。
答案 0 :(得分:8)
您正在寻找的模式是“修改后的身份转换”。此方法的基础是身份转换规则,即下面样式表中的第一个模板规则。之后的每条规则都代表了复制行为的一个例外。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- But strip out <foo> elements (including their content) -->
<xsl:template match="foo"/>
<!-- For <bar> elements, strip out start & end tags, but leave content -->
<xsl:template match="bar">
<xsl:apply-templates/>
</xsl:template>
<!-- For <bat> elements, insert an attribute and append a child -->
<xsl:template match="bat">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="id">123</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对我来说最不满意的是上一个模板规则中的重复逻辑。这只是添加一个属性的很多代码。想象一下,如果我们需要一堆这些。这是另一种方法,它允许我们在我们想要覆盖的内容中更加精确地使用:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<!-- By default, don't add any attributes -->
<xsl:template mode="add-atts" match="*"/>
<!-- For <bat> elements, insert an "id" attribute -->
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
最后,对于您可能想要进行的每种编辑,可以使用不同的模式进一步执行此操作:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- For <bat> elements, insert an "id" attribute -->
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
<!-- Append <new-element/> to <bat> -->
<xsl:template mode="append" match="bat">
<new-element/>
</xsl:template>
<!-- Insert an element in <foo> content -->
<xsl:template mode="insert" match="foo">
<inserted/>
</xsl:template>
<!-- Add content before the <bar/> and <bat/> elements -->
<xsl:template mode="before" match="bar | bat">
<before-bat-and-bar/>
</xsl:template>
<!-- Add content only after <bat/> -->
<xsl:template mode="after" match="bat">
<after-bat/>
</xsl:template>
<!-- Here's the boilerplate code -->
<!-- By default, copy all nodes unchanged -->
<xsl:template match="@* | node()">
<xsl:apply-templates mode="before" select="."/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates mode="insert" select="."/>
<xsl:apply-templates/>
<xsl:apply-templates mode="append" select="."/>
</xsl:copy>
<xsl:apply-templates mode="after" select="."/>
</xsl:template>
<!-- By default, don't add anything -->
<xsl:template mode="add-atts" match="*"/>
<xsl:template mode="insert" match="*"/>
<xsl:template mode="append" match="*"/>
<xsl:template mode="before" match="@* | node()"/>
<xsl:template mode="after" match="@* | node()"/>
</xsl:stylesheet>
在XSLT 2.0中,由于多模式模板规则,一些样板可以略微简化:
<!-- By default, don't add anything -->
<xsl:template mode="add-atts
insert
append
before
after" match="@* | node()"/>
我有时会在同一样式表中使用所有这些自定义模式,但通常我会根据需要懒得添加它们。
答案 1 :(得分:3)
转换XSLT的最大障碍是输出名称空间前缀与转换中的实际XSL指令相同。如果在XSL指令和输出中都使用“xsl:”,那么XSLT引擎将不知道它应该执行的XSL指令与它应该输出的XSL指令之间的区别,因此您的XSLT将不会解析。也就是说,除非您使用命名空间别名:
<xsl:namespace-alias stylesheet-prefix="x" result-prefix="xsl"/>
此指令位于<xsl:stylesheet />
内,允许您使用替换名称空间前缀在转换中编写结果标记。稍后,在创建输出文档时,您实际需要的前缀将插入别名的位置。因此,例如,这是一个在输出文档中生成模板的模板:
<xsl:template match="xsl:template[@match='title']>
<x:template match="title>
<x:apply-templates />
</x:template>
</xsl:template>
答案 2 :(得分:0)
过去我开发了XSL-FO样式表,然后使用Render-X FO2HTML stylesheet将XSL-FO转换为HTML。它会将<block>
元素转换为<div>
,<inline>
转换为<span>
等。
我之前没有使用它们,但您可以考虑尝试HTML2FO stylesheets。或者至少看着他们借用一些想法。
由于HTML缺少FO提供的一些分页结构,它可能无法为您提供XSL-FO输出所需的全部内容,但可能会处理从HTML到XSL-FO元素的大部分转换逻辑/文档正文中的属性。