Sort specific xml nodes - xslt

In the below XML, I need to sort only a specific segment - attrGroupMany name="allergenRelatedInformation" based on the grand child values. And the rest of the XML should be generated as it is with just this segment sorted.
FDA
BIG 8
So all allergenSpecificationAgency that has "FDA" and allergenSpecificationName has "BIG 8" should come before "FDA" and "TREE_NUTS". Please suggest how to achieve this in XSLT. Thanks.
<ns:MT_TradeItemsExport xmlns:ns="test">
<Header version="2.1">
<CreationDateTime>2017-02-09T14:19:03.566Z</CreationDateTime>
<MessageID>0072745000010_9f9cd85e-6d30-4152-a51f-d8491df45486</MessageID>
</Header>
<Payload>
<ItemRegistration>
<attr name="numberOfServingsPerPackage">4.0</attr>
</ItemRegistration>
<attrGroupMany name="organicClaim">
<row>
<attr name="organicTradeItemCode">2</attr>
<attrMany name="organicClaimAgencyCode">
<value>6</value>
</attrMany>
</row>
</attrGroupMany>
<attrGroupMany name="allergenRelatedInformation">
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AC</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AE</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AF</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AM</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AN</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AP</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">AY</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">TREE_NUTS</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">TN</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
<row>
<attr name="allergenSpecificationAgency">FDA</attr>
<attr name="allergenSpecificationName">BIG 8</attr>
<attrGroupMany name="allergen">
<row>
<attr name="allergenTypeCode">UW</attr>
<attr name="levelOfContainmentCode">FREE_FROM</attr>
</row>
</attrGroupMany>
</row>
</attrGroupMany>
</Payload>

You can use xsl:perform-sort or xsl:apply-templates together with xsl:sort, to sort the row children use
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="attrGroupMany[#name ='allergenRelatedInformation']">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="row">
<xsl:sort select="attr[#name = 'allergenSpecificationAgency']"/>
<xsl:sort select="attr[#name = 'allergenSpecificationName']"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:transform>
http://xsltransform.net/ejivdHR

Related

xslt merge sub nodes to one root node

My input document consist of a root with several sub nodes.
...
<root>
<top>
<number>999</number>
<attr attr-name="Numbervalue">
<value>184</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Developer</value>
</attr>
</top>
<top>
<number>999</number>
<attr attr-name="Numbervalue">
<value>1034</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Consultant</value>
</attr>
</top>
</root>
...
I want to merge all subnodes from top into a merged top. Same attributes but different values should result in a multi-valued "value" node. Other nodes/fields (as "number") should be copied. Something like this:
...
<root>
<top>
<number>999</number>
<attr attr-name="Numbervalue">
<value>184</value>
<value>1034</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Developer</value>
<value>Consultant</value>
</attr>
</top>
</root>
...
What i have tried:
...
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="top">
<xsl:for-each select="./attr[#attr-name]">
<xsl:if test="string-length(.)"/>
<xsl:variable name="name" select="./#attr-name"/>
<xsl:variable name="value" select="normalize-space(./value)"/>
<attr>
<xsl:attribute name="attr-name">
<xsl:value-of select="$name"/>
</xsl:attribute>
<value>
<xsl:value-of select="$value"/>
</value>
</attr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...
But this result in:
...
<root>
<attr attr-name="Numbervalue">
<value>184</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Developer</value>
</attr>
<attr attr-name="Numbervalue">
<value>1034</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Consultant</value>
</attr>
</root>
...
With this i am missing the top node and nodes like "number"
If the result looks like this (below) it is also acceptable:
...
<root>
<top>
<number>999</number>
<attr attr-name="Numbervalue">
<value>184</value>
<value>1034</value>
</attr>
<attr attr-name="Initials">
<value>A.C.</value>
<value>A.C.</value>
</attr>
<attr attr-name="Givenname">
<value>Anne</value>
<value>Anne</value>
</attr>
<attr attr-name="Surname">
<value>Bakker</value>
<value>Bakker</value>
</attr>
<attr attr-name="Function">
<value>Developer</value>
<value>Consultant</value>
</attr>
</top>
</root>
...
I am also experimenting with "Muenchian Grouping" but up till now this only results in errors.
A working solution should use only xslt 1.0.
Suggestion are very welcome!
If I am guessing correctly, you want to do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="k1" match="value" use="../#attr-name" />
<xsl:key name="k2" match="value" use="concat(., '|', ../#attr-name)" />
<xsl:template match="/root">
<root>
<top>
<xsl:copy-of select="top[1]/number"/>
<xsl:for-each select="top[1]/attr">
<attr attr-name="{#attr-name}">
<!-- get only distinct values of this attr -->
<xsl:copy-of select="key('k1', #attr-name)[count(. | key('k2', concat(., '|', ../#attr-name))[1]) = 1]"/>
</attr>
</xsl:for-each>
</top>
</root>
</xsl:template>
</xsl:stylesheet>
This takes the list of attr elements from the 1st top, gathers all the value elements that belong to the current attr (using the k1 key), and filters them using the Muenchian grouping expression (utilizing the k2 key) to output only the distinct values among them.

XSLT group every nth item in to new group

I have done few XSLT in the past, but I am facing challenge in this.
I am working with PLC tag, for each tag i am getting three rowset node, so after every three Rowset i need to create new "Row" group.
Updated with XSLT
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<Rowsets >
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<WC_ID>0001</WC_ID>
</Row>
</Rowset>
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<Tag1_Good>6817</Tag1_Good>
</Row>
</Rowset>
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<Tag1_Bad>0</Tag1_Bad>
</Row>
</Rowset>
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<WC_ID>0002</WC_ID>
</Row>
</Rowset>
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<Tag2_Good>6800</Tag2_Good>
</Row>
</Rowset>
<Rowset>
<Row>
<DateTime>2021-07-05T07:33:38</DateTime>
<Tag2_Bad>0</Tag2_Bad>
</Row>
</Rowset>
</Rowsets>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<Rowset>
<Row>
<WC_ID>0001</WC_ID>
<Tag1_Good>6817</Tag1_Good>
<Tag1_Bad>0</Tag1_Bad>
</Row>
<Row>
<WC_ID>0002</WC_ID>
<Tag1_Good>6800</Tag1_Good>
<Tag1_Bad>0</Tag1_Bad>
</Row>
</Rowset>
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Rowsets >
<xsl:variable name="batchSize" select="3"/>
<Rowset>
<xsl:for-each select="/Rowsets/Rowset[position() mod $batchSize >= 0]"
<Row>
<xsl:value-of select="Row/*[2]" />
</Row>
</xsl:for-each>
</Rowset>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
I am not able to make this into a new group
Use this:
<Rowsets>
<xsl:variable name="batchSize" select="3"/>
<Rowset>
<xsl:for-each select="/Rowsets/Rowset">
<xsl:variable name="pos" select="position()"/>
<xsl:if test="$pos mod $batchSize = 0">
<Row>
<WC_ID>
<xsl:value-of select="/Rowsets/Rowset[$pos - 2]/Row/*[2]"/>
</WC_ID>
<Tag1_Good>
<xsl:value-of select="/Rowsets/Rowset[$pos - 1]/Row/*[2]"/>
</Tag1_Good>
<Tag1_Bad>
<xsl:value-of select="/Rowsets/Rowset[$pos]/Row/*[2]"/>
</Tag1_Bad>
</Row>
</xsl:if>
</xsl:for-each>
</Rowset>
</Rowsets>

XSLT grouping multiple levels [duplicate]

I'm trying to group the input below by the destination and assortment values using muenchian-grouping which is new for me so I'm not sure how to do it properly. The input files will be much larger than this so performance is important.
<?xml version="1.0"?>
<ns0:Data xmlns:ns0="http://BizTalk_Projects.input">
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA961</assortment>
<quantity>10</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA961</assortment>
<quantity>15</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA969</assortment>
<quantity>15</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_GA972</assortment>
<quantity>5</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Volvo_SA980</assortment>
<quantity>20</quantity>
</transports>
<transports>
<destination>destination 2</destination>
<assortment>Volvo_GA960</assortment>
<quantity>10</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Nissan_GA963</assortment>
<quantity>5</quantity>
</transports>
<transports>
<destination>destination 1</destination>
<assortment>Nissan_GA963</assortment>
<quantity>5</quantity>
</transports>
</ns0:Data>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Destinations xmlns:ns0="http://BizTalk_Projects.output">
<Destination>
<name>destination 1</name>
<assortment>
<name>Volvo_GA</name>
<row>
<type>sumPerAssortment</type>
<id>961</id>
<totalQuantity>25</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerAssortment</type>
<id>969</id>
<totalQuantity>15</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerAssortment</type>
<id>972</id>
<totalQuantity>5</totalQuantity>
<region>2</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>40</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>5</totalQuantity>
<region>2</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>45</totalQuantity>
<region />
</row>
</assortment>
<assortment>
<name>Volvo_SA</name>
<row>
<type>sumPerAssortment</type>
<id>980</id>
<totalQuantity>20</totalQuantity>
<region>3</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>20</totalQuantity>
<region>3</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>20</totalQuantity>
<region />
</row>
</assortment>
<assortment>
<name>Nissan_GA</name>
<row>
<type>sumPerAssortment</type>
<id>963</id>
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>10</totalQuantity>
<region />
</row>
</assortment>
</Destination>
<Destination>
<name>destination 2</name>
<assortment>
<name>Volvo_GA</name>
<row>
<type>sumPerAssortment</type>
<id>960</id>
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>sumPerRegion</type>
<id />
<totalQuantity>10</totalQuantity>
<region>1</region>
</row>
<row>
<type>totalSum</type>
<id />
<totalQuantity>10</totalQuantity>
<region />
</row>
</assortment>
</Destination>
</ns0:Destinations>
Note:
assortment number starting with 96 = region 1
assortment number starting with 97 = region 2
assortment number starting with 98 = region 3
Start of my XSLT:
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
exclude-result-prefixes="msxsl var s0"
version="1.0"
xmlns:s0="http://BizTalk_Projects.input"
xmlns:ns0="http://BizTalk_Projects.output">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:key name="destinationKey" match="transports" use="destination"/>
<xsl:template match="/">
<xsl:apply-templates select="/s0:Data" />
</xsl:template>
<xsl:template match="/s0:Data">
<ns0:Destinations>
<xsl:for-each select="transports[count(. | key('destinationKey',destination)[1]) = 1]">
<Destination>
<name>
<xsl:value-of select="destination/text()" />
</name>
<xsl:for-each select="key('destinationKey',destination)">
<assortment>
<name>
<xsl:value-of select="substring(assortment/text(),1,string-length(assortment)-3)" />
</name>
</assortment>
</xsl:for-each>
</Destination>
</xsl:for-each>
</ns0:Destinations>
</xsl:template>
</xsl:stylesheet>
With this code, I'm getting this output (duplicate rows, but correct assortments for each destination);
<ns0:Destinations xmlns:ns0="http://BizTalk_Projects.output">
<Destination>
<name>destination 1</name>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_GA</name>
</assortment>
<assortment>
<name>Volvo_SA</name>
</assortment>
<assortment>
<name>Nissan_GA</name>
</assortment>
<assortment>
<name>Nissan_GA</name>
</assortment>
</Destination>
<Destination>
<name>destination 2</name>
<assortment>
<name>Volvo_GA</name>
</assortment>
</Destination>
</ns0:Destinations>
Any suggestions on how I can solve this? Help is very appreciated!
It's difficult to see how exactly the output relates to the input. Try this as your starting point:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="transports-by-destination" match="transports" use="destination" />
<xsl:key name="transports-by-assortment" match="transports" use="concat(destination, '|', assortment)" />
<xsl:template match="/*">
<xsl:copy>
<!-- for each unique destination -->
<xsl:for-each select="transports[count(. | key('transports-by-destination', destination)[1]) = 1]">
<Destination>
<name>
<xsl:value-of select="destination"/>
</name>
<xsl:variable name="group" select="key('transports-by-destination', destination)" />
<!-- for each unique assortment in this destination -->
<xsl:for-each select="$group[count(. | key('transports-by-assortment', concat(destination, '|', assortment))[1]) = 1]">
<assortment>
<name>
<xsl:value-of select="assortment"/>
</name>
<!-- process this subgroup -->
<xsl:for-each select="key('transports-by-assortment', concat(destination, '|', assortment))" >
<row>
<!-- not sure what goes in here -->
<totalQuantity>
<xsl:value-of select="quantity"/>
</totalQuantity>
</row>
</xsl:for-each>
</assortment>
</xsl:for-each>
</Destination>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Grouping elements in XSLT 1.0 and exclude some elements in this grouping

I have the following input XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
<row>
<code>NUMBER</code>
<value>001</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
<row>
<code>NUMBER</code>
<value>002</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
<row>
<code>NUMBER</code>
<value>003</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>NUMBER</code>
<value>004</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE</value>
</row>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
</data>
And it needs to be transformed to the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
<group>
<row>
<code>NUMBER</code>
<value>001</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>002</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE_TO</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>003</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE_FROM</value>
</row>
</group>
<group>
<row>
<code>NUMBER</code>
<value>004</value>
</row>
<row>
<code>TO</code>
<value>NAMELINE</value>
</row>
<row>
<code>FROM</code>
<value>NAMELINE</value>
</row>
</group>
<row>
<code>EXCLUDE</code>
<value>VALUE1</value>
</row>
<row>
<code>EXCLUDEALSO</code>
<value>VALUE2</value>
</row>
</data>
The rules to be applied:
Some rows needs to be excluded from the grouping. These would be the rows that do not have the code NUMBER, FROM or TO.
When code NUMBER appears a new group starts
FROM and TO could be in different order
Rows that have to be exclude will always be in front and/or at the end of the to be grouped codes. It will never appear in between.
In XSLT 2.0 this would be easy and I have the solution, but in XSLT 1.0 I do not know where to start.
Here is a stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="row[code = 'TO' or code = 'FROM']" use="generate-id(preceding-sibling::row[code = 'NUMBER'][1])"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="row[code = 'NUMBER']">
<group>
<xsl:copy-of select=". | key('group', generate-id())"/>
</group>
</xsl:template>
<xsl:template match="row[code = 'FROM' or code = 'TO']"/>
</xsl:stylesheet>

Combining Similar Lines XML

I have an XML record that have repeating unique ID's but would like to combine all similar ID's into 1 record, concat the reference fields and summing up the amount field.
The XML looks like this:
<root>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47582736</F04>
<F05>151.12</F05>
</row>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47643792</F04>
<F05>191.09</F05>
</row>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47643793</F04>
<F05>95.32</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36819319</F04>
<F05>138.87</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36827362</F04>
<F05>9.98</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36834497</F04>
<F05>79.87</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1771929</F04>
<F05>400.07</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1766940</F04>
<F05>111.52</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1810269</F04>
<F05>112.48</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1618234</F04>
<F05>60.76</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1771923</F04>
<F05>2829.19</F05>
</row>
I want to make it look like this:
<root>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>437.53</F03>
<F04>47582736, 47643792, 47643793</F04>
<F05>151.12</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>228.72</F03>
<F04>36819319, 36827362, 36834497</F04>
<F05>138.87</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>3514.02</F03>
<F04>1771929, 1766940, 1810269, 1618234, 1771923</F04>
<F05>400.07</F05>
</row>
I think I may know how to concat F04 but don't know how to sum up F05 and put that value in F03. F01 is the unique ID that should determine what to keep together.
When this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kRowByF02" match="row" use="F02"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<root>
<xsl:apply-templates
select="row[generate-id() = generate-id(key('kRowByF02', F02)[1])]"/>
</root>
</xsl:template>
<xsl:template match="F03">
<F03>
<xsl:value-of
select="sum(key('kRowByF02', preceding-sibling::F02)/F05)" />
</F03>
</xsl:template>
<xsl:template match="F04">
<F04>
<xsl:apply-templates
select="key('kRowByF02', preceding-sibling::F02)/F04/text()"/>
</F04>
</xsl:template>
<xsl:template match="F04/text()">
<xsl:if test="not(position() = 1)">, </xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
...is applied to the provided XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47582736</F04>
<F05>151.12</F05>
</row>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47643792</F04>
<F05>191.09</F05>
</row>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>0</F03>
<F04>47643793</F04>
<F05>95.32</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36819319</F04>
<F05>138.87</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36827362</F04>
<F05>9.98</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>0</F03>
<F04>36834497</F04>
<F05>79.87</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1771929</F04>
<F05>400.07</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1766940</F04>
<F05>111.52</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1810269</F04>
<F05>112.48</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1618234</F04>
<F05>60.76</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>0</F03>
<F04>1771923</F04>
<F05>2829.19</F05>
</row>
</root>
...the wanted result is produced:
<root>
<row>
<F01>123456</F01>
<F02>ABC Company</F02>
<F03>437.53</F03>
<F04>47582736, 47643792, 47643793</F04>
<F05>151.12</F05>
</row>
<row>
<F01>223344</F01>
<F02>DK Corp</F02>
<F03>228.72</F03>
<F04>36819319, 36827362, 36834497</F04>
<F05>138.87</F05>
</row>
<row>
<F01>113964</F01>
<F02>Direct Company</F02>
<F03>3514.02</F03>
<F04>1771929, 1766940, 1810269, 1618234, 1771923</F04>
<F05>400.07</F05>
</row>
</root>
This is a classic grouping problem that, in the case of XSLT 1.0, uses Muenchian Grouping.