Reputation: 104
so I have been having serious issues getting this to work (and I'm sure it is simple, I have little experience with XSL).
I am trying to iterate over a bunch of very different child elements in an xml document that is structured like this:
<transaction>
<data_xml>
<document data_type="0">
<element1>value1</element1>
<element2>value2</element2>
<element3>value3</element3>
</document>
</data_xml>
</transaction>
I am using XSL version 1.0, and I'm pretty sure that I cannot use 2.0 for this considering the constraints of the system I am working in.
The output I want is:
<foo>
<bar:element1><!CDATA[[value]]></bar:element1>
<bar:element2><!CDATA[[value]]></bar:element2>
<bar:element3><!CDATA[[value]]></bar:element3>
</foo>
The awful hideous code I am currently using is:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<foo>
<xsl:for-each select="/transaction/data_xml/document[@data_type='0']/*">
<bar:<xsl:value-of select="name(name(/transaction/data_xml/document[@data_type='0']/*)"/>>
<![CDATA[<xsl:value-of select="/transaction/data_xml/document[@data_type='0']/*"/>]]>
</bar:<xsl:value-of select="name(/transaction/data_xml/document[@data_type='0']/*)"/>>
</xsl:for-each>
</foo>
</xsl:template>
</xsl:stylesheet>
When I use this, though, it just iterates over the same element multiple times, instead of each element in turn.
Any ideas? Besides shooting me for terribad looking code?
Upvotes: 2
Views: 6222
Reputation: 101652
Two things:
name()
or local-name()
with no arguments to get the name of the current element.xsl:element
to create elements with dynamic names. You shouldn't be manually building their tags:<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bar="namespaceForBarGoesHere"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<foo>
<xsl:for-each select="/transaction/data_xml/document[@data_type='0']/*">
<xsl:element name="bar:{local-name()}">
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of select="." />
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:element>
</xsl:for-each>
</foo>
</xsl:template>
Produces this result:
<foo xmlns:bar="namespaceForBarGoesHere">
<bar:element1><![CDATA[value1]]></bar:element1>
<bar:element2><![CDATA[value2]]></bar:element2>
<bar:element3><![CDATA[value3]]></bar:element3>
</foo>
Upvotes: 0
Reputation: 116959
You probably want to do something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bar="http://example.com/bar">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<foo>
<xsl:for-each select="transaction/data_xml/document[@data_type='0']/*">
<xsl:element name="bar:{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</foo>
</xsl:template>
</xsl:stylesheet>
which, applied to your example input, would result in:
<?xml version="1.0" encoding="utf-8"?>
<foo xmlns:bar="http://example.com/bar">
<bar:element1>value1</bar:element1>
<bar:element2>value2</bar:element2>
<bar:element3>value3</bar:element3>
</foo>
If you want the various bar:elementX
values to be CDATA sections, you should specify so in the <xsl:output>
instruction so:
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" cdata-section-elements="bar:element1 bar:element2 bar:element3"/>
However this requires you to know all possible element names in advance. Otherwise you'd have to hack it, for example as:
<xsl:template match="/">
<foo>
<xsl:for-each select="transaction/data_xml/document[@data_type='0']/*">
<xsl:element name="bar:{local-name()}">
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of select="."/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:element>
</xsl:for-each>
</foo>
</xsl:template>
Upvotes: 2