sblandin
sblandin

Reputation: 964

Transform element attributes into sub-elements

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

Answers (1)

Ian Roberts
Ian Roberts

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

Related Questions