似乎有很多类似的问题,但没有一个对我有帮助。我想重构下面的XSLT:
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="/forms//instance[@versionNumber = '1']/content//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="/forms//instance[@versionNumber = '2']/content//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="/forms//instance[@versionNumber = '3']/content//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
注意更改versionNumber属性。
xml源看起来像这样:
<forms>
<instance versionNumber="3">
<content>
<textbox id="1">THREE</textbox>
</content>
<previousVersions>
<instance versionNumber="1">
<content>
<textbox id="1">ONE</textbox>
</content>
</instance>
<instance versionNumber="2">
<content>
<textbox id="1">TWO</textbox>
</content>
</instance>
</previousVersions>
</instance>
</forms>
输出应该是一个格式如下的表行:
+-----+-----+-------+
| ONE | TWO | THREE |
+-----+-----+-------+
在代码中,这看起来像这样:
<table-cell>ONE</table-cell>
<table-cell>TWO</table-cell>
<table-cell>THREE</table-cell>
这很容易,不使用循环计数器,但是我总是需要3个单元格,无论有多少个版本。如果没有versionNumber = 3的实例,则表格必须如下所示:
+-----+-----+-----+
| ONE | TWO | |
+-----+-----+-----+
或者用XML:
<table-cell>ONE</table-cell>
<table-cell>TWO</table-cell>
<table-cell></table-cell>
答案 0 :(得分:2)
没有循环但有其他模板:
<xsl:template match="instance">
<xsl:param name="id" />
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="content//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
</xsl:template>
<!-- in another template... -->
<xsl:apply-templates select="/forms//instance[@id = $instanceId and (@versionNumber >= 1 and @versionNumber <= 3)]">
<xsl:with-param name="id" select="$id"/>
<xsl:sort select="@versionNumber" data-type="number"/>
</xsl:apply-templates>
答案 1 :(得分:1)
无论有多少版本,我总是需要3个单元格。
只有三个单元格,您可以简单地对它们进行硬编码。如果您不想这样做,那么将必须使用循环,例如:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="instance" match="instance" use="@versionNumber" />
<xsl:template match="/forms">
<root>
<xsl:call-template name="generate-cells">
<xsl:with-param name="n" select="3" />
</xsl:call-template>
</root>
</xsl:template>
<xsl:template name="generate-cells">
<xsl:param name="n"/>
<xsl:if test="$n">
<!-- recursive call -->
<xsl:call-template name="generate-cells">
<xsl:with-param name="n" select="$n - 1" />
</xsl:call-template>
<!-- current cell -->
<table-cell>
<xsl:value-of select="key('instance', $n)/content/textbox" />
</table-cell>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
在函数式语言中,我可以调用&#39; map&#39;在集合[1,2,3]和 从那里开始,有没有XSLT相当于这样做?
在XSLT 2.0中,您可以执行以下操作:
<xsl:template match="/forms">
<xsl:variable name="forms" select="." />
<root>
<xsl:for-each select="('1','2','3')">
<table-cell>
<xsl:value-of select="key('instance', ., $forms)/content/textbox" />
</table-cell>
</xsl:for-each>
</root>
</xsl:template>
甚至:
<xsl:for-each select="1 to 3">
<table-cell>
<xsl:value-of select="key('instance', string(.), $forms)/content/textbox" />
</table-cell>
</xsl:for-each>
答案 2 :(得分:1)
来自评论:
我需要准确地拥有3个表格单元格,无论有多少个实例节点,即使只有1个或2个。
然后你可以使用一个小技巧并循环遍历三个不相关的节点并滥用position()
:
<xsl:for-each select="//*[position() <= 3]">
<xsl:variable name="i" select="position()" />
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="content/forms//instance[@versionNumber = $i]//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
</xsl:for-each>
或者您可以使用递归,这对于XSLT来说更为惯用。它适用于任意数量的重复,但也更长:
<xsl:template name="output-table-cell">
<xsl:param name="i" />
<xsl:param name="max" />
<xsl:if test="$i <= $max">
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="content/forms//instance[@versionNumber = $i]//textbox[@id = $id]/text()" />
</fo:block>
</fo:table-cell>
<!-- recursive step -->
<xsl:call-template name="output-table-cell">
<xsl:with-param name="i" select="$i + 1" />
<xsl:with-param name="max" select="$max" />
</xsl:call-template>
</xsl:if>
</xsl:template>
请注意,我假设在两个片段中的其他地方都定义了$id
。根据需要进行调整。
答案 3 :(得分:0)
受@ michael.hor257k的启发,我最终没有循环,而是创建了一个命名模板并调用了3次。这足以减少代码重复并使其更清晰:
<xsl:call-template name="table-cell">
<xsl:with-param name="node" select="/forms//instance[@versionNumber = '1']/content//textbox[@id = $id]" />
</xsl:call-template>
<xsl:call-template name="table-cell">
<xsl:with-param name="node" select="/forms//instance[@versionNumber = '2']/content//textbox[@id = $id]" />
</xsl:call-template>
<xsl:call-template name="table-cell">
<xsl:with-param name="node" select="/forms//instance[@versionNumber = '3']/content//textbox[@id = $id]" />
</xsl:call-template>
<xsl:template name="tableCell">
<xsl:param name="node" />
<fo:table-cell xsl:use-attribute-sets="table-item-bordered">
<fo:block>
<xsl:value-of select="$node/text()" />
</fo:block>
</fo:table-cell>
</xsl:template>