Reputation: 3598
I'm pretty new to XSLT and have an urgent work requirement that I'm finding quite complex to sort out.
I have an XML doc which needs an attribute adding under certain conditions.
The XML doc is pretty straightforward:
<A x="foo" y="bar" z="">
<B/>
<C/></A>
Basically if attribute "z" is present. Then a new attribute needs to be added to node "A". The value of the attribute needs to be a text string with the values of "x" and "y" substituted at certain places. The result should look like:
<A x="foo" y="bar" z="" new="values present are x=foo and y=bar">
<B/>
<C/></A>
I've gotten as far as creating an XSLT that will copy the document to the attribute level. But I'm stumbling when trying to create the logic that tests for attribute z and creates a string based on x and y.
Can anyone help?
Thanks
Also - apologies if my code formatting sucks
From comments:
There's something that's stopping these solutions working. The text XML I've put above actually has a root node
<R>
that contains it all. The R node has an attribute like this :xmlns="http://www.fixprotocol.org/FIXML-4-4"
. Adding this attribute for some reason causes the template matching "A" to not work?!
Upvotes: 1
Views: 1924
Reputation:
EDIT: Now with correct namespace.
This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fixml="http://www.fixprotocol.org/FIXML-4-4">
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fixml:A/@z">
<xsl:call-template name="identity"/>
<xsl:attribute name="new">
<xsl:value-of
select="concat('values present are x=',../@x,' and y=',../@y)"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
With this input:
<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
<A x="foo" y="bar" z="">
<B/>
<C/>
</A>
</R>
Output:
<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
<A x="foo" y="bar" z="" new="values present are x=foo and y=bar">
<B></B>
<C></C>
</A>
</R>
Upvotes: 1
Reputation: 243579
Updated: The OP has explained (only in a comment!):
There's something that's stopping these solutions working. The text XML I've put above actually has a root node that contains it all. The
<R>
node has an attribute like this :xmlns="http://www.fixprotocol.org/FIXML-4-4"
. Adding this attribute for some reason causes the template matching "A" to not work?!
This is probably as short as it can be:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://www.fixprotocol.org/FIXML-4-4"
xmlns="http://www.fixprotocol.org/FIXML-4-4" exclude-result-prefixes="x">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="x:A[@z]">
<A new="values present are x={@x} and y={@y}">
<xsl:apply-templates select="node()|@*"/>
</A>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
<A x="foo" y="bar" z="">
<B/>
<C/>
</A>
</R>
the wanted, correct result is produced:
<R xmlns="http://www.fixprotocol.org/FIXML-4-4">
<A new="values present are x=foo and y=bar" x="foo" y="bar" z="">
<B></B>
<C></C>
</A>
</R>
Upvotes: 3
Reputation: 567
You can use the following XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A">
<A>
<xsl:if test="@z">
<xsl:attribute name="new">
<xsl:value-of select="concat('values present are x=',@x,' and y=',@y)"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@* | node()"/>
</A>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1