I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<DocumentElement>
<Invoice>
<Header Misc="5.00" TotalAmount="33.00" />
<Packages>
<Package>
<Lines>
<Line>
<LineCharge Amount="28.00" />
</Line>
</Lines>
</Package>
<Package>
<Lines>
<Line>
<LineCharge Amount="0.00" />
</Line>
</Lines>
</Package>
</Packages>
</Invoice>
</DocumentElement>
And applied the following template to move the Misc attribute and its value from the Header element, created a new Element called LineCharge and assigned the value of Misc to it.
<?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" xmlns:xe="urn:XSLTExtender"
exclude-result-prefixes="msxsl">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="@*|node()" >
<xsl:copy>
<xsl:apply-templates select="@*[normalize-space()]|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@Misc" />
<xsl:template match ="LineCharge[1]" >
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
<xsl:if test="normalize-space(//Invoice/Header/@Misc) != '' and number(//Invoice/Header/@Misc) = normalize-space(//Invoice/Header/@Misc)">
<xsl:element name ="LineCharge">
<xsl:attribute name="Chargecd" >
<xsl:value-of select="'CD01'"/>
</xsl:attribute>
<xsl:attribute name="Amount" >
<xsl:value-of select="//Invoice/Header/@Misc"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I got the following output:
<DocumentElement><Invoice>
<Header TotalAmount="33.00" />
<Packages>
<Package>
<Lines>
<Line>
<LineCharge Amount="28.00" />
<LineCharge Chargecd="CD01" Amount="5.00" />
</Line>
</Lines>
</Package>
<Package>
<Lines>
<Line>
<LineCharge Amount="0.00" />
<LineCharge Chargecd="CD01" Amount="5.00" />
</Line>
</Lines>
</Package>
</Packages>
</Invoice></DocumentElement>
The TotalAmount should be 33.00 (i.e. 28.00 5.00), but since the new LineCharge element is being repeated for each Package element, the Total is now 38.00, which is wrong.
How do I get the following output where the Misc value is only moved to the first Package element, and not its siblings:
<DocumentElement><Invoice>
<Header TotalAmount="33.00" />
<Packages>
<Package>
<Lines>
<Line>
<LineCharge Amount="28.00" />
<LineCharge Chargecd="CD01" Amount="5.00" />
</Line>
</Lines>
</Package>
<Package>
<Lines>
<Line>
<LineCharge Amount="0.00" />
</Line>
</Lines>
</Package>
</Packages>
</Invoice></DocumentElement>
CodePudding user response:
You could use xsl:key to get a key of all LineCharge elements and just match the first one...
<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="line_charge" match="LineCharge" use="''"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@Misc"/>
<xsl:template match="LineCharge[generate-id()=generate-id(key('line_charge','')[1])]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<LineCharge Chargecd="CD01" Amount="{//Header/@Misc}" />
</xsl:template>
</xsl:stylesheet>
Fiddle: http://xsltfiddle.liberty-development.net/eieFA1Z
CodePudding user response:
Why not simply:
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="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Package[1]/Lines/Line[1]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<LineCharge Chargecd="CD01" Amount="{ancestor::Invoice/Header/@Misc}" />
</xsl:copy>
</xsl:template>
<xsl:template match="@Misc"/>
</xsl:stylesheet>