I have the following XML:
<DocumentElement>
<Sheet1>
<FIELD_1>HD</FIELD_1>
<FIELD_2>2024</FIELD_2>
<FIELD_3>90655</FIELD_3>
<FIELD_13>667</FIELD_13>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_2>496</FIELD_2>
<FIELD_13>0339618701316335</FIELD_13>
<FIELD_22>DMax</FIELD_22>
<FIELD_30>8.41</FIELD_30>
<FIELD_65>0.16</FIELD_65>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_2>496</FIELD_2>
<FIELD_13>0339618701316335</FIELD_13>
<FIELD_22>Sign</FIELD_22>
<FIELD_30>2.50</FIELD_30>
</Sheet1>
</DocumentElement>
The following stylesheet is creating the XML that follows:
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:msxsl='urn:schemas-microsoft-com:xslt' xmlns:var='urn:var' xmlns:user='urn:user' exclude-result-prefixes='msxsl var user' version='1.0'>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/DocumentElement">
<DocumentElement>
<xsl:choose>
<xsl:when test="normalize-space(/DocumentElement/Sheet1[1]/FIELD_1) = 'HD' and normalize-space(/DocumentElement/Sheet1[2]/FIELD_1) = 'DT'">
<xsl:apply-templates select="Sheet1[normalize-space(FIELD_1) = 'HD' and normalize-space(FIELD_2) != 'CusId' and normalize-space(FIELD_2) != 'CusID']" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="Sheet1[number(FIELD_2) = FIELD_2 and normalize-space(FIELD_1) != 'DT']" />
</xsl:otherwise>
</xsl:choose>
</DocumentElement>
</xsl:template>
<xsl:template priority="1" match="Sheet1[normalize-space(FIELD_1) = 'HD']">
<Invoice>
<Ships>
<xsl:variable name="prevC" select="count(preceding-sibling::*[normalize-space(FIELD_1) = 'DT' and FIELD_2 != 'CustomerId' and FIELD_2 != 'TrackingNbr'])"/>
<xsl:variable name="newC" select="count(following-sibling::*[normalize-space(FIELD_1) = 'HD'][1]/preceding-sibling::*[normalize-space(FIELD_1) = 'DT' and FIELD_2 != 'CustomerId' and FIELD_2 != 'TrackingNbr'])"/>
<xsl:variable name="pos" select="count(following-sibling::*[ normalize-space(FIELD_1) = 'HD'][1])" />
<xsl:apply-templates select="following-sibling::*[normalize-space(FIELD_1) = 'DT'][position() < ($newC - $prevC + 1) or $pos = 0]" >
<xsl:with-param name="data" select="FIELD_3" />
</xsl:apply-templates>
</Ships>
</Invoice>
</xsl:template>
<xsl:template priority="1" match="Sheet1[normalize-space(FIELD_1) = 'DT']" >
<xsl:param name="scac"/>
<Ship>
<Lines>
<Line>
<xsl:attribute name="ReferenceNumber" >
<xsl:value-of select="normalize-space(FIELD_13)"/>
</xsl:attribute>
<LineCharge >
<xsl:attribute name="Charge" >
<xsl:choose>
<xsl:when test="normalize-space(FIELD_22) = 'Sign'">
<xsl:value-of select="'TS5'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'TS0'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="Amount" >
<xsl:value-of select="format-number(translate(FIELD_30,'$,()',''),'###0.00')"/>
</xsl:attribute>
</LineCharge>
</Line>
</Lines>
</Ship>
</xsl:template>
</xsl:stylesheet>
XML OUTPUT:
<DocumentElement>
<Invoice>
<Ships>
<Ship>
<Lines>
<Line ReferenceNumber="0339618701316335">
<LineCharge Charge="TS0" Amount="8.41"/>
<LineCharge Charge="TS2" Amount="0.16"/>
</Line>
</Lines>
</Ship>
<Ship>
<Lines>
<Line ReferenceNumber="0339618701316335">
<LineCharge Charge="TS0" Amount="2.50"/>
</Line>
</Lines>
</Ship>
</Ships>
</Invoice>
</DocumentElement>
The first goal: Create one Ship element whenever there are multiple Sheet1 elements with identical values in FIELD_13. The following if statement was added above in the code to prevent the second Ship element from being captured:
<xsl:if test="not(preceding-sibling::*[normalize-space(FIELD_1) = 'DT' and FIELD_13 = current()/FIELD_13])">
NEW OUTPUT shows only one Ship element, which is correct:
<DocumentElement>
<Invoice>
<Ships>
<Ship>
<Lines>
<Line ReferenceNumber="0339618701316335">
<LineCharge Charge="TS0" Amount="8.41"/>
</Line>
</Lines>
</Ship>
</Ships>
</Invoice>
</DocumentElement>
The new issue is that the second LineCharge element is now skipped.
<LineCharge Charge="TS0" Amount="2.50"/>
I still need the 2nd LineCharge element that was nested in the second Ship element, but this time, as a sub element in the first Ship element, as seen below:
<DocumentElement>
<Invoice>
<Ships>
<Ship>
<Lines>
<Line ReferenceNumber="0339618701316335">
<LineCharge Charge="TS0" Amount="8.41"/>
<LineCharge Charge="TS5" Amount="2.50"/>
</Line>
</Lines>
</Ship>
</Ships>
</Invoice>
</DocumentElement>
How do I achieve this final XML?
I appreciate any assistance with this.
Here is an example of Muenchian grouping that may get you started:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="key1" match="Sheet1[FIELD_1='DT']" use="FIELD_13"/>
<xsl:template match="/DocumentElement">
<DocumentElement>
<Invoice>
<Ships>
<!-- group by FIELD_13 -->
<xsl:for-each select="Sheet1[FIELD_1='DT'][generate-id()=generate-id(key('key1', FIELD_13)[1])]">
<Ship>
<Lines>
<Line ReferenceNumber="{FIELD_13}">
<!-- process current group -->
<xsl:for-each select="key('key1', FIELD_13)">
<LineCharge Charge="" Amount="{FIELD_30}"/>
</xsl:for-each>
</Line>
</Lines>
</Ship>
</xsl:for-each>
</Ships>
</Invoice>
</DocumentElement>
</xsl:template>
</xsl:stylesheet>
With XML input of:
<DocumentElement>
<Sheet1>
<FIELD_1>HD</FIELD_1>
<FIELD_13>100</FIELD_13>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_13>101</FIELD_13>
<FIELD_30>8.41</FIELD_30>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_13>101</FIELD_13>
<FIELD_30>2.50</FIELD_30>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_13>102</FIELD_13>
<FIELD_30>5.62</FIELD_30>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_13>103</FIELD_13>
<FIELD_30>4.59</FIELD_30>
</Sheet1>
<Sheet1>
<FIELD_1>DT</FIELD_1>
<FIELD_13>103</FIELD_13>
<FIELD_30>9.97</FIELD_30>
</Sheet1>
</DocumentElement>
you will get:
<?xml version="1.0"?>
<DocumentElement>
<Invoice>
<Ships>
<Ship>
<Lines>
<Line ReferenceNumber="101">
<LineCharge Charge="" Amount="8.41"/>
<LineCharge Charge="" Amount="2.50"/>
</Line>
</Lines>
</Ship>
<Ship>
<Lines>
<Line ReferenceNumber="102">
<LineCharge Charge="" Amount="5.62"/>
</Line>
</Lines>
</Ship>
<Ship>
<Lines>
<Line ReferenceNumber="103">
<LineCharge Charge="" Amount="4.59"/>
<LineCharge Charge="" Amount="9.97"/>
</Line>
</Lines>
</Ship>
</Ships>
</Invoice>
</DocumentElement>