XSLT to copy XML doc and add attribute plus generated value under certain conditions
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 actuall开发者_运维知识库y 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?!
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>
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>
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>
精彩评论