Warm tip: This article is reproduced from stackoverflow.com, please click
xml xslt

XSLT to transform in a XML some tags with the count of every tag

发布于 2020-04-07 23:16:41

How can I transform an XML that has something like this:

<info>
   .....
   <name>aaa</name>
</info>
<info>
   .....
   <name>bbb</name>
</info>
<info>
   .....
   <name>ccc</name>
</info>

with an XSLT into something like this:

<info>
   .....
   <name1>aaa</name1>
</info>
<info>
   .....
   <name2>bbb</name2>
</info>
<info>
   .....
   <name3>ccc</name3>
</info>

Anyone has any idea? Thanks!

Questioner
WDrgn
Viewed
28
Martin Honnen 2020-02-01 04:08

I would suggest to use xsl:number instead of sibling count:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

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

  <xsl:template match="info/name">
      <xsl:variable name="pos">
          <xsl:number count="info"/>
      </xsl:variable>
      <xsl:element name="{name()}{$pos}">
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ejivJs7

Or in XSLT 3 use an accumulator (works even with streaming):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy" use-accumulators="info-count" streamable="yes"/>

  <xsl:accumulator name="info-count" as="xs:integer" initial-value="0" streamable="yes">
      <xsl:accumulator-rule match="info" select="$value + 1"/>
  </xsl:accumulator>

  <xsl:template match="info/name">
      <xsl:element name="{name()}{accumulator-before('info-count')}">
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ejivJs7/1