Yoona May
Yoona May

Reputation: 93

reset counter in xslt v2.0

Consider my XML File:

<Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR date="080817"/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date="080817"/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date="080817"/>
</Data>

I need to add an attribute seq in <VetaR>, this attribute is a counter for every VetaR created. But, I need to reset the counter for every 5 occurrences of <VetaR>. I need to add also an attribute cnt, in which, it is also a counter, but this time it will only increment for every 5 occurrences of <VetaR>. I need to remove also the empty attributes.

Here is my XSLT code:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Data">
    <xsl:copy>
        <xsl:for-each-group select="*" group-adjacent="(position() - 1) idiv 5">
            <xsl:apply-templates select="current-group()">
                <xsl:with-param name="group-pos" select="position()"/>
            </xsl:apply-templates>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="VetaR">
    <xsl:param name="group-pos"/>
    <VetaR seq="{position()}" cnt="{$group-pos}">
        <xsl:apply-templates select="@*"/>
    </VetaR>
</xsl:template>

<xsl:template match="VetaR/@*[not(normalize-space())]"/>

Current Output:

<Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR seq="3" cnt="1" date="080817"/>
  <VetaR seq="4" cnt="1"/>
  <VetaR seq="5" cnt="1"/>
  <VetaR seq="1" cnt="2"/>
  <VetaR seq="2" cnt="2" date="080817"/>
  <VetaR seq="3" cnt="2"/>
  <VetaR seq="4" cnt="2"/>
  <VetaR seq="5" cnt="2" date="080817"/></Data>

Desired Output:

  <Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR seq="1" cnt="1" date="080817"/>
  <VetaR seq="2" cnt="1"/>
  <VetaR seq="3" cnt="1"/>
  <VetaR seq="4" cnt="1"/>
  <VetaR seq="5" cnt="1" date="080817"/>
  <VetaR seq="1" cnt="2"/>
  <VetaR seq="2" cnt="2"/>
  <VetaR seq="3" cnt="2" date="080817"/></Data>

Upvotes: 0

Views: 558

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167716

I would tackle it as positional grouping:

<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:output indent="yes"/>

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

    <xsl:template match="Data">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="(position() - 1) idiv 5">
                <xsl:apply-templates select="current-group()">
                    <xsl:with-param name="group-pos" select="position()"/>
                </xsl:apply-templates>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="VetaR">
        <xsl:param name="group-pos"/>
        <VetaR seq="{position()}" cnt="{$group-pos}">
            <xsl:apply-templates select="@*"/>
        </VetaR>
    </xsl:template>

    <xsl:template match="VetaR/@*[not(normalize-space())]"/>
</xsl:stylesheet>

Upvotes: 2

michael.hor257k
michael.hor257k

Reputation: 117102

Why not simply:

<xsl:template match="VetaR">
    <VetaR seq="{(position() - 1)  mod 5 + 1}" cnt="{(position() - 1) idiv 5 + 1}">
        <xsl:if test="string(@date)">
            <xsl:copy-of select="@date"/>
        </xsl:if>
     </VetaR>
</xsl:template>

Upvotes: 2

Related Questions