Reputation:
I have an XML like this:
<V>
<W>
<X>1</X>
</W>
<W>
<Y>1</Y>
</W>
<W>
<X>1555</X>
</W>
<W>
<X>1</X>
</W>
</V>
I want to make it something like this:
<entity ID="start">
<f ID="NewField">0001</f>
<f ID="NewField">0001</f>
<f ID="NewField">0002</f>
<f ID="NewField">0003</f>
</entity>
When the field is V/W/X then NewField
should be incremented by 1 as many times the tag V/W/X is found.
Similarly for V/W/Y.
The XSL which I am using is
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<entity ID="start">
<xsl:for-each select="V/W">
<xsl:if test="X">
<xsl:variable name="my_var">
<xsl:value-of select="concat('000',position())"/>
</xsl:variable>
<f ID="NewField"><xsl:value-of select="$my_var"/></f>
</xsl:if>
<xsl:if test="Y">
<xsl:variable name="my_var">
<xsl:value-of select="concat('000',position())"/>
</xsl:variable>
<f ID="NewField"><xsl:value-of select="$my_var"/></f>
</xsl:if>
</xsl:for-each>
</entity>
</xsl:template>
</xsl:stylesheet>
but it gives me a wrong result, something like this:
<entity ID="start">
<f ID="NewField">0001</f>
<f ID="NewField">0002</f>
<f ID="NewField">0003</f>
<f ID="NewField">0004</f>
</entity>
Upvotes: 1
Views: 3227
Reputation: 167716
If you want to number nodes with XSLT then the xsl:number element can help:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<entity ID="start">
<xsl:apply-templates select="descendant::X | descendant::Y"/>
</entity>
</xsl:template>
<xsl:template match="X | Y">
<f ID="NewField"><xsl:number level="any" format="0000"/></f>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 338376
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="V">
<entity ID="start">
<xsl:apply-templates select="W/X|W/Y" />
</entity>
</xsl:template>
<xsl:template match="X|Y">
<f ID="NewField">
<xsl:variable name="counter" select="
count(
parent::W/preceding-sibling::W/*[name() = name(current())]
) + 1
" />
<xsl:value-of select="format-number($counter, '0000')" />
</f>
</xsl:template>
</xsl:stylesheet>
This:
parent::W/preceding-sibling::W/*[name() = name(current())]
selects all preceding elements of the same name as the current element. E.g., if the point of execution is on this node:
<X>1555</X>
It goes one level up (parent::W
), then selects all preceding <W>
siblings, and of those it selects any child (*
) that has a name of X
- since X
is the name of the current()
element.
The resulting node-set is counted and incremented by one. format-number()
is used to generate a nice clean output:
<entity ID="start">
<f ID="NewField">0001</f>
<f ID="NewField">0001</f>
<f ID="NewField">0002</f>
<f ID="NewField">0003</f>
</entity>
Upvotes: 0
Reputation: 143269
I think you're looking for something like count(preceding::X)
expression. Of course you may want to make it more complex and then take care about number formatting, but that sounds like a starting point you're looking for.
Upvotes: 0