Reputation: 188
I ran into an issue regarding attributes on a node not showing when the <xsl:apply-templates>
is used during an <xsl:copy>
. I wanted to add a child node within my copy, at the top. However, I found that when I did the added node, followed by
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
I ended up with no attributes on the parent node.
Code Examples:
Message to be Transformed
<XMLMessage>
<Name>QueryResponse</Name>
<Content>
<Object status="Approved">
<Slot name="languageCode">
<ValueList>
<Value>en-us</Value>
</ValueList>
</Slot>
</Object>
</Content>
</XMLMessage>
This first XSLT results in no attributes coming across with the <Object>
. My end goal was to have the added <Slot>
above the languageCode slot, but I end up with no @Status
attribute on the <Object>
tag.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//Object[not(Slot/@name='AddedValue')]">
<xsl:copy>
<Slot name="AddedValue">
<ValueList>
<Value>
<xsl:value-of select="'Value to Add'"/>
</Value>
</ValueList>
</Slot>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result:
<XMLMessage>
<Name>QueryResponse</Name>
<Content>
<Object>
<Slot name="AddedValue">
<ValueList>
<Value>Value to Add</Value>
</ValueList>
</Slot>
<Slot name="languageCode">
<ValueList>
<Value>en-us</Value>
</ValueList>
</Slot>
</Object>
</Content>
</XMLMessage>
Second Transformation, with the <apply-templates>
above the added <Slot>
, results in the @Status
attribute being included, but the added <Slot>
is now below the original node.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//Object[not(Slot/@name='AddedValue')]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
<Slot name="AddedValue">
<ValueList>
<Value>
<xsl:value-of select="'Value to Add'"/>
</Value>
</ValueList>
</Slot>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result:
<XMLMessage>
<Name>QueryResponse</Name>
<Content>
<Object status="Approved">
<Slot name="languageCode">
<ValueList>
<Value>en-us</Value>
</ValueList>
</Slot>
<Slot name="AddedValue">
<ValueList>
<Value>Value to Add</Value>
</ValueList>
</Slot>
</Object>
</Content>
</XMLMessage>
I would like to understand why the attribute does not come across with the first transformation. What attribute is it "trying" to get? The attribute of the "languageCode" <Slot>
?
How could I get the "AddedValue" <Slot>
above the "languageCode" <Slot>
while retaining the @Status
attribute?
Upvotes: 0
Views: 25
Reputation: 116993
According to the XSLT specification, adding an attribute to an element after children have been added to it is an error. Create all attributes first, then create the child nodes:
<xsl:template match="Object[not(Slot/@name='AddedValue')]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<Slot name="AddedValue">
<ValueList>
<Value>
<xsl:value-of select="'Value to Add'"/>
</Value>
</ValueList>
</Slot>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
Upvotes: 1