In the below input we have to check the supplier code if it is match to any of the node supplier code then we have to perform sum operation on Quantity.otherwise directly map the quantity.
input:
<Move-Afile>
<Afile>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>1234</PackNumber>
<Quantity>12</Quantity>
</Item>
<Item>
<suppliercode>2</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>3</Quantity>
</Item>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>8</Quantity>
</Item>
<Item>
<suppliercode>3</suppliercode>
<PackNumber>126</PackNumber>
<Quantity>11</Quantity>
</Item>
<Item>
<suppliercode>4</suppliercode>
<PackNumber>876</PackNumber>
<Quantity>32</Quantity>
</Item>
</Afile>
</Move-Afile>
If supplier code is equal then perform sum operation on Quantity,otherwise directly map the Quantity.
output:
<A>
<target>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>1234</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>2</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>3</Quantity>
</Item>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>3</suppliercode>
<PackNumber>126</PackNumber>
<Quantity>11</Quantity>
</Item>
<Item>
<suppliercode>4</suppliercode>
<PackNumber>876</PackNumber>
<Quantity>32</Quantity>
</Item>
</target>
</A>
i need the sum logic in a separate temporary variable like below.
<varaible name=tempvar>
<xsl:choose>
<xsl:when suppliercode=suppliercode>
<xsl:value-of select=sum(quntity)/>
<xsl:when>
<xsl:otherwise>
<xsl:value-of select=quntity/>
</xsl:otherwise>
</xsl:choose>
</variable>
This stylesheet does what you require. It copies all elements from Item
downwards, and has a special template to change the value of Quantity
by adding the values of all Quantity
elements from Item
elements that have the same value of suppliercode
.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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="Move-Afile/Afile/Item"/>
</target>
</A>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Quantity">
<xsl:variable name="supplier-code" select="parent::Item/suppliercode"/>
<xsl:copy>
<xsl:value-of select="sum(ancestor::Afile/Item[suppliercode = $supplier-code]/Quantity)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
output
<A>
<target>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>1234</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>2</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>3</Quantity>
</Item>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>3</suppliercode>
<PackNumber>126</PackNumber>
<Quantity>11</Quantity>
</Item>
<Item>
<suppliercode>4</suppliercode>
<PackNumber>876</PackNumber>
<Quantity>32</Quantity>
</Item>
</target>
</A>
Update
To put the total into a variable before using it, you can replace the last template with this
<xsl:template match="Quantity">
<xsl:variable name="supplier-code" select="parent::Item/suppliercode"/>
<xsl:variable name="total" select="sum(ancestor::Afile/Item[suppliercode = $supplier-code]/Quantity)"/>
<xsl:copy>
<xsl:value-of select="$total"/>
</xsl:copy>
</xsl:template>
which sets the value of $total
to the sum of the quantities with the same suppplier code.
This short and efficient (using a key) transformation:
<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="kQuantityBySupplier" match="Quantity" use="../suppliercode"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<A>
<target>
<xsl:apply-templates select="*/node()"/>
</target>
</A>
</xsl:template>
<xsl:template match="Quantity/text()">
<xsl:value-of select="sum(key('kQuantityBySupplier', ../../suppliercode))"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<Move-Afile>
<Afile>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>1234</PackNumber>
<Quantity>12</Quantity>
</Item>
<Item>
<suppliercode>2</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>3</Quantity>
</Item>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>8</Quantity>
</Item>
<Item>
<suppliercode>3</suppliercode>
<PackNumber>126</PackNumber>
<Quantity>11</Quantity>
</Item>
<Item>
<suppliercode>4</suppliercode>
<PackNumber>876</PackNumber>
<Quantity>32</Quantity>
</Item>
</Afile>
</Move-Afile>
produces the wanted, correct result:
<A>
<target>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>1234</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>2</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>3</Quantity>
</Item>
<Item>
<suppliercode>1</suppliercode>
<PackNumber>567</PackNumber>
<Quantity>20</Quantity>
</Item>
<Item>
<suppliercode>3</suppliercode>
<PackNumber>126</PackNumber>
<Quantity>11</Quantity>
</Item>
<Item>
<suppliercode>4</suppliercode>
<PackNumber>876</PackNumber>
<Quantity>32</Quantity>
</Item>
</target>
</A>
Do note:
The time complexity of this transformation is linear (O(N)). This can be orders of magnitude more efficient than repeatedly scanning all elements to find the ones having a given suppliercode
-- which has quadratical (O(N^2)) time complexity.
Update:
The OP has specified a new requirement, that the sum or the single quantity be captured in a variable:
Just modify this:
<xsl:template match="Quantity/text()">
<xsl:value-of select="sum(key('kQuantityBySupplier', ../../suppliercode))"/>
</xsl:template>
into this:
<xsl:template match="Quantity/text()">
<xsl:variable name="vSum" select="sum(key('kQuantityBySupplier', ../../suppliercode))"/>
<xsl:value-of select="$vSum"/>
</xsl:template>