Reputation: 93
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
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
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