在嵌套模板中添加标点符号

时间:2016-03-11 05:56:40

标签: xslt xslt-2.0

我想在<album>中添加带逗号和空格的元素,如果它不是父<album>中的最后一个<recording>

我有一个<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>

2 个答案:

答案 0 :(得分:1)

将您的第二个(匹配集合)模板更改为

<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元素,并将其他录制子项的调用移至录制模板。

最初,您正在循环记录元素并将模板应用于内容节点。因此,您永远不会允许录制模板匹配任何内容。通过将模板应用于当前上下文节点,我们正在使用录制节点本身而不是其内容,以允许录制模板匹配。

此外,在录制模板中,您要添加逗号元素而不是 x 元素。我已将这些更改为上面的 x 元素,因为这是您似乎想要的。

此外,甚至不需要您的第一个xsl:for-each。如果我们将位置测试从集合模板移动到录制模板,我们可以简化集合模板以避免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="*"/>

本文中的所有示例均使用OP的原始示例以及其他xsl:strip-space元素和<xsl:output method="xml" indent="yes"/>使用 Saxon-HE 9.7.0.2J 进行测试,产生的结果相当于OP所需的输出直到缩进( x 元素出现在它们自己的行上)。

答案 1 :(得分:0)

我要做的是创建一个与recordingalbum匹配的模板,如果它不是同类中的第一个,请输出<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>