Reputation: 65496
I have xml like this:
<configurationData>
<path name='b'>
<path name='a'>
<setting name='s1'>
![CDATA[XXXX]]
</setting>
<setting name='s2'>
XXXX
</setting>
</path>
</path>
</configurationData>
where configurationData is the root node, and there can be may nested paths followed by one or more setting nodes. I want to convert the setting node to put the contents of the setting node into a child node called value
<configurationData>
<path name='b'>
<path name='a'>
<setting name='s1'>
<value>![CDATA[XXXX]]</value>
</setting>
<setting name='s2'>
<value>XXXX</value>
</setting>
</path>
</path>
</configurationData>
I must admit I find XML a mental road block and I cannot see what XSLT to use:
This is my attempt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding ="utf-8" indent="yes" method="xml" version="1.0"/>
<xsl:template match='/setting'>
<xsl:apply-templates select='setting' />
</xsl:template>
<xsl:template match='setting'>
<value>
<xsl:value-of select='.'/>
</value>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 653
Reputation: 86774
You are 90% of the way there. What you need is the "identity template"
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding ="utf-8" indent="yes" method="xml" version="1.0"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match='setting'>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<value>
<xsl:value-of select='.'/>
</value>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The first template processes all nodes, copying them to the output. However, the 'setting' template, being more specific, gets invoked for 'setting' nodes, That template copies the node itself and its attributes, then wraps the value in a 'value' tag.
The most non-intiutive thing about XSLT is that the stylesheet is not a program which drives the process. Instead, it is the input XML document that controls, with the stylesheet providing instructions that get selected and executed according to what's in the input. This is called "push" processing. The XSL processor pushes data to your stylesheet. XSLT does have some procedural capabilities, and you can write a stylesheet in "pull" style, where the stylesheet attempts to drive the process, but this is harder and leads to hard-to-maintain stylesheets.
Edit: To enable CDATA sections replace:
<xsl:value-of select='.' />
with
![CDATA[<xsl:value-of select='.' disable-output-escaping="yes"/>]]
(though not the best solution as it always puts CDATA in)
Upvotes: 3
Reputation: 338208
My suggestion, based on Jim Garrison answer:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" encoding="utf-8" cdata-section-elements="value" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="setting/text()">
<value>
<xsl:value-of select="." />
</value>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0