Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT: copy attributes from child element

Tags:

xslt

Input:

 <a q='r'>
   <b x='1' y='2' z='3'/>
   <!-- other a content -->
 </a>

Desired output:

 <A q='r' x='1' y='2' z='3'>
   <!-- things derived from other a content, no b -->
 </A>

Could someone kindly give me a recipe?

like image 527
bmargulies Avatar asked Mar 16 '11 21:03

bmargulies


2 Answers

Easy.

<xsl:template match="a">
  <A>
    <xsl:copy-of select="@*|b/@*" />
    <xsl:apply-templates /><!-- optional -->
  </A>
</xsl:template>

The <xsl:apply-templates /> is not necessary if you have no further children of <a> you want to process.

Note

  • the use of <xsl:copy-of> to insert source nodes into the output unchanged
  • the use of the union operator | to select several unrelated nodes at once
  • that you can copy attribute nodes to a new element as long as it is the first thing you do - before you add any child elements.

EDIT: If you need to narrow down which attributes you copy, and which you leave alone, use this (or a variation of it):

<xsl:copy-of select="(@*|b/@*)[
  name() = 'q' or name() = 'x' or name() = 'y' or name() = 'z'
]" />

or even

<xsl:copy-of select="(@*|b/@*)[
  contains('|q|x|y|z|', concat('|', name(), '|'))
]" />

Note how the parentheses make the predicate apply to all matched nodes.

like image 134
Tomalak Avatar answered Nov 02 '22 10:11

Tomalak


XSL

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="a">
        <A>
            <xsl:apply-templates select="@*|b/@*|node()"/>
        </A>
    </xsl:template>

    <xsl:template match="b"/>

</xsl:stylesheet>

output

<A q="r" x="1" y="2" z="3"><!-- other a content --></A>
like image 41
Daniel Haley Avatar answered Nov 02 '22 11:11

Daniel Haley