Reputation: 157
here is my requirement i need to write an XSLT that will transform the node name according to there occurence see my example
XML PRESENT :
<Orders>
<Order>
<OrderNo>ABC</OrderNo>
<ItemDetails>
<Name>Shirt</Name>
<Name>Socks</Name>
<ItemPrice>30</ItemPrice>
<ItemPrice>40</ItemPrice>
</ItemDetails>
</Order>
</Orders>
XML NEEDED
<Orders>
<Order>
<OrderNo>ABC</OrderNo>
<ItemDetails>
<Name1>Shirt</Name>
<Name2>Socks</Name>
<ItemPrice1>30</ItemPrice>
<ItemPrice2>40</ItemPrice>
</ItemDetails>
</Order>
</Orders>
Check the Name and item price anem . Like this i have 100 of order in an xml of ORDERS
Upvotes: 0
Views: 105
Reputation: 122364
This is possible using a stylesheet based on the identity transformation to copy most of the XML unchanged and just tweak the little bits that you want to change:
<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="ItemDetails/*">
<xsl:element name="{name()}{count(
preceding-sibling::*[name() = name(current())]) + 1}">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
If you want to leave the first occurrence of each element alone and start numbering from the second one then you could do this in XSLT 2.0 by tweaking the template match pattern:
<xsl:template match="ItemDetails/*[preceding-sibling::*[name() = name(current())]]">
<xsl:element name="{name()}{count(
preceding-sibling::*[name() = name(current())])}">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:template>
But in XSLT 1.0 you can't use current()
in a match
pattern so instead you'll have to do the check inside the body of the template, e.g.
<xsl:template match="@*|node()" name="ident">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="ItemDetails/*">
<xsl:choose>
<xsl:when test="preceding-sibling::*[name() = name(current())]">
<xsl:element name="{name()}{count(
preceding-sibling::*[name() = name(current())])}">
<xsl:apply-templates select="@*|node()" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<!-- this is the first element with this name, so revert to the
identity behaviour -->
<xsl:call-template name="ident" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
On a more general level this is a rather poor choice of XML format - it's more usual to use the same name for elements that denote the same kind of data, and to express the dependencies between different elements via nesting rather than positioning, e.g.
<ItemDetails>
<Item>
<Name>Shirt</Name>
<Price>30</Price>
</Item>
<Item>
<Name>Socks</Name>
<Price>40</Price>
</Item>
</ItemDetails>
Upvotes: 1