在嵌套模板中添加标点符号
Adding punctuation in nested templates
我正在尝试在 <album>
中添加带有逗号和 space 的元素,如果它不是父元素 <recording>
中的最后一个 <album>
。
我有一个用于 <recording>
的类似模板,可以按预期工作。但是,我无法使 <album>
标点符号的第二个模板正常工作。
我认为这与现有的第一个模板有关...
输入XML
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
示例 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="collection">
<xsl:copy>
<xsl:for-each select="recording">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<comma>, </comma>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
但是我的输出是
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording><x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
而不是我想要的(注意<x>
,在第一个<album>
之后在第二个<recording>
)
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording><x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album><x>, </x>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>
将你的第二个(匹配集合)模板更改为
<xsl:template match="collection">
<xsl:copy>
<xsl:for-each select="recording">
<xsl:apply-templates select="."/>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
并将您的录音模板修改为
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
删除 xsl:copy
元素并将其替换为 xsl:apply-templates
元素并将对其他录音子项的调用移动到 recording 模板中。
就目前而言,您正在遍历记录元素并将模板应用于内容节点。因此,您永远不允许 recording 模板匹配任何内容。通过将模板应用于当前上下文节点,我们正在使用 recording 节点本身而不是其内容,从而允许 recording 模板匹配。
此外,在您的 recording 模板中,您要添加 comma 元素而不是 x 元素。我已将这些更改为上面的 x 元素,因为这似乎是您想要的。
此外,您的第一个 xsl:for-each
甚至都不需要。如果我们将位置测试从 collection 模板移动到 recording 模板,我们可以简化 collection 模板避免 xsl:for-each
:
<xsl:template match="collection">
<xsl:copy>
<xsl:apply-templates select="recording"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:for-each>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:template>
我们甚至可以对专辑做同样的事情,消除两个 xsl:for-each
元素
<xsl:template match="collection">
<xsl:copy>
<xsl:apply-templates select="recording"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:apply-templates select="album"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:template>
<xsl:template match="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:template>
以上所有内容都会复制完全为空白的元素之间的文本节点,这可能是不可取的。将以下内容添加到样式表的顶部将防止出现这种情况:
<xsl:strip-space elements="*"/>
此 post 中的所有示例均使用带有附加 xsl:strip-space
元素的 OP 原始示例进行测试,<xsl:output method="xml" indent="yes"/>
使用 Saxon-HE 9.7.0.2J 并产生相当于 OP 所需输出的结果,直至缩进(x 元素出现在它们自己的行上)。
我要做的是创建一个匹配 recording
或 album
的模板,如果它不是同类中的第一个,则输出 <x>, </x>
.
XML 输入
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording|album">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<xsl:if test="$count > 1"><x>, </x></xsl:if>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<x>, </x>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>
我正在尝试在 <album>
中添加带有逗号和 space 的元素,如果它不是父元素 <recording>
中的最后一个 <album>
。
我有一个用于 <recording>
的类似模板,可以按预期工作。但是,我无法使 <album>
标点符号的第二个模板正常工作。
我认为这与现有的第一个模板有关...
输入XML
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
示例 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="collection">
<xsl:copy>
<xsl:for-each select="recording">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<comma>, </comma>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
但是我的输出是
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording><x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
而不是我想要的(注意<x>
,在第一个<album>
之后在第二个<recording>
)
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording><x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album><x>, </x>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>
将你的第二个(匹配集合)模板更改为
<xsl:template match="collection">
<xsl:copy>
<xsl:for-each select="recording">
<xsl:apply-templates select="."/>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
并将您的录音模板修改为
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
删除 xsl:copy
元素并将其替换为 xsl:apply-templates
元素并将对其他录音子项的调用移动到 recording 模板中。
就目前而言,您正在遍历记录元素并将模板应用于内容节点。因此,您永远不允许 recording 模板匹配任何内容。通过将模板应用于当前上下文节点,我们正在使用 recording 节点本身而不是其内容,从而允许 recording 模板匹配。
此外,在您的 recording 模板中,您要添加 comma 元素而不是 x 元素。我已将这些更改为上面的 x 元素,因为这似乎是您想要的。
此外,您的第一个 xsl:for-each
甚至都不需要。如果我们将位置测试从 collection 模板移动到 recording 模板,我们可以简化 collection 模板避免 xsl:for-each
:
<xsl:template match="collection">
<xsl:copy>
<xsl:apply-templates select="recording"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:for-each select="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:for-each>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:template>
我们甚至可以对专辑做同样的事情,消除两个 xsl:for-each
元素
<xsl:template match="collection">
<xsl:copy>
<xsl:apply-templates select="recording"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording">
<xsl:copy>
<xsl:apply-templates select="(node() | @*) except album"/>
<xsl:apply-templates select="album"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<xsl:element name="x">, </xsl:element>
</xsl:if>
</xsl:template>
<xsl:template match="album">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
<xsl:if test="position()!=last()">
<x>, </x>
</xsl:if>
</xsl:template>
以上所有内容都会复制完全为空白的元素之间的文本节点,这可能是不可取的。将以下内容添加到样式表的顶部将防止出现这种情况:
<xsl:strip-space elements="*"/>
此 post 中的所有示例均使用带有附加 xsl:strip-space
元素的 OP 原始示例进行测试,<xsl:output method="xml" indent="yes"/>
使用 Saxon-HE 9.7.0.2J 并产生相当于 OP 所需输出的结果,直至缩进(x 元素出现在它们自己的行上)。
我要做的是创建一个匹配 recording
或 album
的模板,如果它不是同类中的第一个,则输出 <x>, </x>
.
XML 输入
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="recording|album">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<xsl:if test="$count > 1"><x>, </x></xsl:if>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<sample>
<collection>
<recording>
<artist>Radiohead</artist>
<album>OK Computer</album>
</recording>
<x>, </x>
<recording>
<artist>Tori Amos</artist>
<album>Boys For Pele</album>
<x>, </x>
<album>To Venus And Back</album>
</recording>
</collection>
</sample>