joe
joe

Reputation: 17478

How to Copy children using XSL

How do I copy children using XSL?

Source:

<body>
   <keyword><i color="blue">super</i>man</keyword>
   <keyword><i color="blue">super</i>man</keyword>
   <keyword><i color="blue">super</i>woman</keyword>
</body>

I am using the following

  <xsl:template match="keyword" >
    <keyword>
      <xsl:attribute name="type">Key Words Head First</xsl:attribute>

      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </keyword>

  </xsl:template>

When using the above code I am getting double nested <keyword> tags.

Thanks.

Upvotes: 2

Views: 720

Answers (2)

Wayne
Wayne

Reputation: 60414

You don't need to output a keyword explicitly and copy the existing keyword using xsl:copy. As an alternative to @DevNull's answer:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="keyword">
        <xsl:copy>
            <xsl:attribute name="type">Key Words Head First</xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

...produces the following, when applied to your input:

<body>
    <keyword type="Key Words Head First"><i color="blue">super</i>man</keyword>
    <keyword type="Key Words Head First"><i color="blue">super</i>man</keyword>
    <keyword type="Key Words Head First"><i color="blue">super</i>woman</keyword>
</body>

From the comments:

...what if the attribute needs to be overridden. Like suppose 'keyword' already has a 'type' attribute.

In that case, don't copy the existing type attribute:

<xsl:template match="keyword">
    <xsl:copy>
        <xsl:attribute name="type">Key Words Head First</xsl:attribute>
        <xsl:apply-templates select="@*[not(name()='type')]|node()"/>
    </xsl:copy>
</xsl:template>

Upvotes: 3

Daniel Haley
Daniel Haley

Reputation: 52858

xsl:copy is copying the context item, which in this case is keyword. Basically you're wrapping the existing keyword with a new one.

Try removing the xsl:copy:

  <xsl:template match="keyword" >
    <keyword type="Key Words Head First">
      <xsl:apply-templates select="node()|@*[name() != 'type']"/>
    </keyword>    
  </xsl:template>

Note: Your final output will depend on whether you have other templates to handle the children of keyword (like an identity transform).

You can find more information on copying and the identity transform here: http://www.w3.org/TR/xslt#copying

Upvotes: 3

Related Questions