如何使用XSLT将所有这些XML标记连接成一个同名的大标记?

时间:2012-08-08 18:58:07

标签: xml xslt xpath-1.0


我正在改变这个XML:

<root>
  <contrib contrib-type="author">
    <name>
      <last-name>Kottke</last-name>
      <first-name>Leo</first-name>
    </name>
  </contrib>

  <contrib contrib-type="author">
    <name>
      <last-name>McKee</last-name>
      <first-name>Andy</first-name>
    </name>
  </contrib>

  <contrib contrib-type="author">
    <name>
      <last-name>Hedges</last-name>
      <first-name>Michael</first-name>
    </name>
  </contrib>
</root>

...用这个XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>

    <!-- identity rule -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

        <!-- Authors -->
        <xsl:template match="contrib[@contrib-type='author']">
            <Authors>
              <xsl:if test="position() != last()">
                <xsl:value-of select = "concat(name/first-name, ' ', name/last-name, ', ')" />
              </xsl:if>

              <xsl:if test="position() = last()">
                <xsl:value-of select = "concat('and ', name/first-name, ' ', name/last-name, '.')" />
              </xsl:if>
            </Authors>
        </xsl:template>
</xsl:stylesheet>

...我得到了这个输出:

<root>
    <Authors>Leo Kottke, </Authors>
    <Authors>Andy McKee, </Authors>
    <Authors>and Michael Hedges.</Authors>
</root>


<小时/>

但是,我尝试将所有Author标记连接到一个较大的Author标记中,以便输出类似于

<root>
    <Authors>Leo Kottke, Andy McKee, and Michael Hedges.</Authors>
</root>


我是否需要以某种方式使用for-each循环?

2 个答案:

答案 0 :(得分:2)

不需要xsl:for-each。只需为/*(或/root)添加模板,然后从Authors匹配项中删除contrib

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>

    <!-- identity rule -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/root">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <Authors>
                <xsl:apply-templates select="contrib[@contrib-type='author']"/>
            </Authors>
        </xsl:copy>
    </xsl:template>

    <!-- Authors -->
    <xsl:template match="contrib[@contrib-type='author']">
        <xsl:if test="position() != last()">
            <xsl:value-of select = "concat(name/first-name, ' ', name/last-name, ', ')" />
        </xsl:if>

        <xsl:if test="position() = last()">
            <xsl:value-of select = "concat('and ', name/first-name, ' ', name/last-name, '.')" />
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:2)

更简单的东西

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/root">
        <xsl:variable name="authors">
            <xsl:for-each select="contrib/name">
                <xsl:text>, </xsl:text>
                <xsl:value-of select="first-name"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="last-name"/>
            </xsl:for-each>
        </xsl:variable>

        <root>
            <authors><xsl:value-of select="substring($authors,3)"/></authors>
        </root>
    </xsl:template>

</xsl:stylesheet>