Reputation: 373
This is the input XML:
<Move-Afile>
<Afile>
<Item>
<PackNumber>1234</PackNumber>
</Item>
<Item>
<PackNumber>567</PackNumber>
</Item>
<Item>
<PackNumber>567</PackNumber>
</Item>
<Item>
<PackNumber>126</PackNumber>
</Item>
<Item>
<PackNumber>876</PackNumber>
</Item>
</Afile>
</Move-Afile>
<Item>
is an unbounded element which contains <PackNumber>
as a child element. For each pack number we need to increment the counter variable, but here one condition is present like if previous <PackNumber>
is equal to current <PackNumber>
we have to ignore the counter (there is no need to increment) like below output.
Inside the for-each
, can we get the counter like below XSLT sample?
This is my XSLT template
<xsl:template match="/">
<A>
<target>
<xsl:for-each select="/inp1:Move-Afile/inp1:Afile/inp1:Item/inp1:PalletNumber">
<xsl:variable name="count">
<!-- get the count here-->
</xsl:variable>
<counter>$count</counter>
<PNumber><xsl:value-of select="."/></PNumber>
</xsl:for-each>
</target>
</A>
</xsl:template>
This is the XML output:
<A>
<target>
<Item>
<counter>1</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
<PNumber>1234</PNumber>
</Item>
<Item>
<counter>2</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
<PNumber>567</PNumber>
</Item>
<Item><!-- if previous <PackNumber> is equal to current <PackNumber> ignore the count-->no need to increment
<PNumber>567</PNumber>
</Item>
<Item>
<counter>3</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
<PNumber>126</PNumber>
</Item>
<Item><!-- if previous <PackNumber> is equal to current <PackNumber> ignore the count-->no need to increment
<PNumber>126</PNumber>
</Item>
</target>
</A>
XML output 2:
<?xml version="1.0"?>
<A>
<target>
<counter>1</counter>
<PNumber>1234</PNumber>
<counter>2</counter>
<PNumber>567</PNumber>
<!-- IF PNumber is equal we have to ignore the Total loop -->
<counter>3</counter>
<PNumber>126</PNumber>
<counter>4</counter>
<PNumber>876</PNumber>
</target>
</A>
Upvotes: 4
Views: 25258
Reputation: 1
Rather than using counter variable and attempting to increment its value every time (Which anyway not going to happen as the variables in xsl are actually constants), try using position()
, which can work as a unique incrementing identifier. Following is an example of the syntax using position()
:
<xsl:variable name="counterAlias" select="position()"/>
Upvotes: -1
Reputation: 243579
Here is a short and very efficient solution, using Muenchian grouping:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPackNByVal" match="PackNumber" use="."/>
<xsl:template match="Afile">
<A>
<target>
<xsl:apply-templates select=
"*/*[generate-id() = generate-id(key('kPackNByVal',.)[1])]"/>
</target>
</A>
</xsl:template>
<xsl:template match="PackNumber">
<counter><xsl:value-of select="position()"/></counter>
<PNumber><xsl:value-of select="."/></PNumber>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Move-Afile>
<Afile>
<Item>
<PackNumber>1234</PackNumber>
</Item>
<Item>
<PackNumber>567</PackNumber>
</Item>
<Item>
<PackNumber>567</PackNumber>
</Item>
<Item>
<PackNumber>126</PackNumber>
</Item>
<Item>
<PackNumber>876</PackNumber>
</Item>
</Afile>
</Move-Afile>
the wanted, correct result is produced:
<A>
<target>
<counter>1</counter>
<PNumber>1234</PNumber>
<counter>2</counter>
<PNumber>567</PNumber>
<counter>3</counter>
<PNumber>126</PNumber>
<counter>4</counter>
<PNumber>876</PNumber>
</target>
</A>
Upvotes: 3
Reputation: 126762
If the result you need is what you show in your second XML sample, then this stylesheet is all you need.
All it does is copy the PackNumber
from only those Item
elements that have no previous matching PackNumber
.
The count is calculated as one more than the number of preceding Item
elements that have no matching predecessor.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="/">
<A>
<target>
<xsl:apply-templates select="*"/>
</target>
</A>
</xsl:template>
<xsl:template match="Item">
<xsl:if test="not(PackNumber = preceding-sibling::Item/PackNumber)">
<counter>
<xsl:value-of select="1+count(preceding-sibling::Item[not(PackNumber = preceding-sibling::Item/PackNumber)])"/>
</counter>
<xsl:copy-of select="PackNumber"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
output
<A>
<target>
<counter>1</counter>
<PackNumber>1234</PackNumber>
<counter>2</counter>
<PackNumber>567</PackNumber>
<counter>3</counter>
<PackNumber>126</PackNumber>
<counter>4</counter>
<PackNumber>876</PackNumber>
</target>
</A>
Upvotes: 1
Reputation: 9627
Try this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" />
<xsl:template match="PackNumber">
<xsl:if test="not(preceding::PackNumber =.)" >
<!-- if previous <PackNumber> is not equal to current <PackNumber> t-->
<counter>
<xsl:value-of select="count(preceding::PackNumber[not(preceding::PackNumber= .)])+1"/>
</counter>
</xsl:if>
<PNumber>
<xsl:value-of select="."/>
</PNumber>
</xsl:template>
<xsl:template match="/">
<A>
<target>
<xsl:apply-templates select="//Item"/>
</target>
</A>
</xsl:template>
</xsl:stylesheet>
Update according the changed question:
get the count here (inside a for each loop as variable)
Try this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" />
<xsl:template match="PackNumber" mode="count">
<xsl:value-of select="count(preceding::PackNumber
[not(preceding::PackNumber= .)and not( . = current()/. ) ])+1"/>
</xsl:template>
<xsl:template match="/">
<A>
<target>
<xsl:for-each select="//Item/PackNumber">
<xsl:variable name="count">
<xsl:apply-templates select="." mode="count"/>
</xsl:variable>
<counter>
<xsl:value-of select="$count"/>
</counter>
<PNumber>
<xsl:value-of select="."/>
</PNumber>
</xsl:for-each>
</target>
</A>
</xsl:template>
</xsl:stylesheet>
Update Output:
<?xml version="1.0"?>
<A>
<target>
<counter>1</counter>
<PNumber>1234</PNumber>
<counter>2</counter>
<PNumber>567</PNumber>
<counter>2</counter>
<PNumber>567</PNumber>
<counter>3</counter>
<PNumber>126</PNumber>
<counter>4</counter>
<PNumber>876</PNumber>
</target>
</A>
Upvotes: 4