Reputation: 13
it's my first time using XSL and i have a hard task to do.
I would like to merge and add specific nodes from my XML.
For Example:
XML:
<Root>
<Result>ok</Result>
<Type>SingleObject</Type>
<Head>
<DocumentLines>
<line0>
<LineNum>0</LineNum>
<ItemCode>A1234</ItemCode>
<Dscription>Article1</Dscription>
<Quantity>5</Quantity>
</line0>
<line1>
<LineNum>1</LineNum>
<ItemCode>B4321</ItemCode>
<Dscription>Article2</Dscription>
<Quantity>6</Quantity>
</line1>
<line2>
<LineNum>2</LineNum>
<ItemCode>A789</ItemCode>
<Dscription>Article3</Dscription>
<Quantity>8</Quantity>
</line2>
<line3>
<LineNum>3</LineNum>
<ItemCode>A1234</ItemCode>
<Dscription>Article1</Dscription>
<Quantity>5</Quantity>
</line3>
</DocumentLines>
</Head>
</Root>
Based off of the ItemCode i would like to merge line 0 and line 3 and add the Quantity together like this:
<Document_Lines>
<row>
<LineNum>0</LineNum>
<ItemCode>A1234</ItemCode>
<Dscription>Article1</Dscription>
<Quantity>10</Quantity>
</row>
<row>
<LineNum>1</LineNum>
<ItemCode>B4321</ItemCode>
<Dscription>Article2</Dscription>
<Quantity>6</Quantity>
</row>
<row>
<LineNum>2</LineNum>
<ItemCode>A789</ItemCode>
<Dscription>Article3</Dscription>
<Quantity>8</Quantity>
</row>
</Document_Lines>
My XSL looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<Document_Lines>
<xsl:for-each select="/Root/Head/DocumentLines/*">
<xsl:variable name="index" select="1"/>
<row>
<LineNum><xsl:value-of select="LineNum[$index]" /></LineNum>
<ItemCode> <xsl:value-of select="ItemCode[$index]" /> </ItemCode>
<Dscription><xsl:value-of select="Dscription[$index]" /></Dscription>
<Quantity><xsl:value-of select="Quantity[$index]" /></Quantity>
</row>
</xsl:for-each>
</Document_Lines>
</xsl:template>
</xsl:stylesheet>
It gets all the Lines and shows them correctly but i dont really know how to progress further from here. Hope someone can help
Upvotes: 0
Views: 37
Reputation: 29052
For an ordered output in XSLT-1.0, you have to apply the Muenchian Grouping method. There are many examples for this approach on SO.
Applied to your personal situation, the code could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="lines" match="*[starts-with(local-name(),'line')]" use="ItemCode" />
<xsl:template match="/">
<Document_Lines>
<xsl:for-each select="/Root/Head/DocumentLines/*[generate-id()=generate-id(key('lines',ItemCode))]">
<row>
<LineNum><xsl:value-of select="LineNum" /></LineNum>
<ItemCode><xsl:value-of select="ItemCode" /> </ItemCode>
<Description><xsl:value-of select="Dscription" /></Description>
<Quantity><xsl:value-of select="sum(key('lines',ItemCode)/Quantity)" /></Quantity>
</row>
</xsl:for-each>
</Document_Lines>
</xsl:template>
</xsl:stylesheet>
The Muenchian Grouping consists of two parts:
xsl:key name="values" ...
generate-id()=key(...)
Both parts together let you group the line?
elements the way you want.
The output is:
<?xml version="1.0"?>
<Document_Lines>
<row>
<LineNum>0</LineNum>
<ItemCode>A1234</ItemCode>
<Description>Article1</Description>
<Quantity>10</Quantity>
</row>
<row>
<LineNum>1</LineNum>
<ItemCode>B4321</ItemCode>
<Description>Article2</Description>
<Quantity>6</Quantity>
</row>
<row>
<LineNum>2</LineNum>
<ItemCode>A789</ItemCode>
<Description>Article3</Description>
<Quantity>8</Quantity>
</row>
</Document_Lines>
An improved XSLT-2.0 solution could be
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<Document_Lines>
<xsl:for-each-group select="/Root/Head/DocumentLines/*[starts-with(local-name(),'line')]" group-by="ItemCode">
<row>
<xsl:copy-of select="LineNum, ItemCode, Dscription" />
<Quantity><xsl:value-of select="sum(current-group()/Quantity)" /></Quantity>
</row>
</xsl:for-each-group>
</Document_Lines>
</xsl:template>
</xsl:stylesheet>
Its output is the same.
Upvotes: 1