I need to transform XML using xslt.
Logic:
Split the parent if the parent having different child address and append the sequence number with parent name. Also need line number for the child. Here we may have number of parent nodes and each parent node may have more number of child nodes.
I have tried numerous ways to achieve this and I am stuck with generating sequence number in the foreach. So can any one try and give a solution for this.
Source XML as below:
<Data>
<Parent>
<Name>P1</Name>
<Child>
<Name>CName1</Name>
<Address>Address1</Address>
</Child>
<Child>
<Name>CName2</Name>
<Address>Address2</Address>
</Child>
<Child>
<Name>CName3</Name>
<Address>Address1</Address>
</Child>
</Parent>
<Parent>
<Name>P2</Name>
<Child>
<Name>CName1</Name>
<Addr开发者_如何学Pythoness>Address1</Address>
</Child>
</Parent>
</Data>
The target XML should be as below:
<Data>
<Parent>
<Name>P1_1</Name>
<Address>Address1</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName1</Name>
</Child>
<Child>
<LineNumber>2</LineNumber>
<Name>CName3</Name>
</Child>
</Parent>
<Parent>
<Name>P1_2</Name>
<Address>Address2</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName2</Name>
</Child>
</Parent>
<Parent>
<Name>P2_1</Name>
<Address>Address1</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName1</Name>
</Child>
</Parent>
</Data>
This XSLT 1.0 transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kAddress" match="Child" use="concat(generate-id(..), '|', Address)" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Parent">
<xsl:variable name="parent" select="." />
<xsl:for-each select="Child[
generate-id()
=
generate-id(key('kAddress', concat(generate-id($parent), '|', Address))[1])
]">
<Parent>
<Name><xsl:value-of select="concat(../Name, '_', position())" /></Name>
<xsl:copy-of select="Address" />
<xsl:apply-templates select="
key('kAddress', concat(generate-id($parent), '|', Address))
" />
</Parent>
</xsl:for-each>
</xsl:template>
<xsl:template match="Child">
<xsl:copy>
<xsl:copy-of select="@*" />
<LineNumber><xsl:value-of select="position()" /></LineNumber>
<xsl:apply-templates select="node()[not(self::Address)]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Generates the following output for your sample:
<Data>
<Parent>
<Name>P1_1</Name>
<Address>Address1</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName1</Name>
</Child>
<Child>
<LineNumber>2</LineNumber>
<Name>CName3</Name>
</Child>
</Parent>
<Parent>
<Name>P1_2</Name>
<Address>Address2</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName2</Name>
</Child>
</Parent>
<Parent>
<Name>P2_1</Name>
<Address>Address1</Address>
<Child>
<LineNumber>1</LineNumber>
<Name>CName1</Name>
</Child>
</Parent>
</Data>
精彩评论