Entomo
Entomo

Reputation: 275

XSLT transform child element to attribute in the parent

<?xml version="1.0"?>
<parent id="38" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <child id="1" colorType="firstColor" colorKey="blue"/>
  <child id="2" colorType="secondColor" colorKey="red"/>
</parent>

So I have the previous XML and I would like to transform it, using XSLT, in the following way:

<?xml version="1.0"?>
<parent id="38" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
firstColor="blue" secondColor="red">
</parent>

So two values from the child element to be used as a pair attribute in the parent, removing the child element in the process. I tried but can't wrap my head around what seems to be the basics of XSLT.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="parent">
    <parent>
      <xsl:apply-templates/>
    </parent>
  </xsl:template>

  <xsl:template match="parent">
    <parent>
      <xsl:attribute name="{@colorType}">
        <xsl:value-of select="@colorKey"/>
      </xsl:attribute>
     </parent>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 1970

Answers (2)

Abel
Abel

Reputation: 57189

I would go for something like the following, i.e., simply applying templates to child and matching it, so that each child will turn into attributes:

<xsl:template match="parent">
    <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="child" />
    </xsl:copy>
</xsl:template>

<xsl:template match="child">
    <xsl:attribute name="{@colorType}" select="@colorKey" />
</xsl:template>

I generally prefer applying templates to for-each'ing over a set of nodes, as it is usually easier to adapt later, and is (generally) easier to follow.

Upvotes: 1

Tim C
Tim C

Reputation: 70648

You are on the right lines, but you actually need to create an attribute for each child element under parent, so you could use xsl:for-each here:

Try replacing your parent template with this:

<xsl:template match="parent">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="child">
            <xsl:attribute name="{@colorType}">
                <xsl:value-of select="@colorKey" />
            </xsl:attribute>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

Also note the use of xsl:copy-of to copy the existing attributes. Also note the use of <xsl:copy> instead of just doing <parent> as this will ensure the namespace declaration for "xsi" is copied too.

Upvotes: 3

Related Questions