Reputation: 63
Is there anyway of converting an xml so that the values within each element become attributes of that element e.g
<example>
<abc>12</abc>
<def>hello</def>
</example>
becomes:
<example>
<abc val=12/>
<def val=hello/>
</example>
but everything else is left the same
sorry forgot to say that i would ideally like a script which achieves this no matter what xml you give it.
Upvotes: 0
Views: 91
Reputation: 167461
Write a template
<xsl:template match="example/*[not(*)]">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:attribute name="val" select="."/>
</xsl:element>
</xsl:template>
plus the identity transformation template of course
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
If you want to transform all elements not having any child elements to the format <foo val="..."/>
then change the template match pattern from <xsl:template match="example/*[not(*)]">
to <xsl:template match="*[not(*)]">
. Also note that I used the XSLT 2.0 syntax <xsl:attribute name="val" select="."/>
, with an XSLT 1.0 processor you would need <xsl:attribute name="val"><xsl:value-of select="."/></xsl:attribute>
.
As for having a working approach for any kind of XML document, well, if you have <foo><bar><baz>foobar</baz></bar><bar>value</bar></foo>
, then the simple approach would throw an error as the attribute creation would happen after the child element creation. It is not clear which result order you want, so you would need to edit your question and show us more details of possible input and wanted result samples.
Upvotes: 0
Reputation: 1377
Something like that should work:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="no" encoding="UTF-8" indent="yes" />
<xsl:template match="example">
<xsl:element name="{name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="example/*">
<xsl:element name="{name()}">
<xsl:attribute name="val"><xsl:value-of select="."/></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:transform>
However, depending on the structure of your real life input, you might need to change the template selectors.
Upvotes: 1