Reputation: 964
I have some xml fragments that looks like this
<an_element1 attribute1="some value" attribute2="other value" ... attributeN="N value">
<an_element2 attribute1="some value" attribute2="other value" ... attributeN="N value">
...
I need to transform it in something like this:
<an_element1>
<attribute1>some value</attribute1>
<atttibute2>other value</attribute2>
...
<attributeN>N value</attributeN>
</an_element1>
<an_element2>
<attribute1>some value</attribute1>
<atttibute2>other value</attribute2>
...
<attributeN>N value</attributeN>
</an_element2>
...
I have already succesfully tried some examples found in other answers, but I wanted to know if there is a sort of generic approach to this problem that can be summarized like this:
for each element named an_element create a sub-element for each of its attributes each containing their respective values.
Since the repeating elements may contain duplicated values (two an_element items with identical values for all their attributes) I wanted to know if it is possible to filter only unique elements.
If the filter is possible it's better to apply it before or after the transformation?
Upvotes: 1
Views: 132
Reputation: 122364
for each element named an_element create a sub-element for each of its attributes each containing their respective values.
The following stylesheet converts all attributes into like-named elements. Elements generated from attributes will precede elements copied from the child elements in the source.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XST/Transform" version="1.0">
<xsl:template match="@*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If you only want to do this for elements with a particular name you need something more like
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XST/Transform" version="1.0">
<xsl:template match="an_element/@*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
which would convert
<an_element foo="bar"/>
into
<an_element>
<foo>bar</foo>
</an_element>
but would leave <another_element attr="whatever"/>
unchanged.
Upvotes: 1