2

Example xml is:

<a amp="a"><b><c>this is the text</c></b></a>

Needs to be transformed to:

<a amp="a"><c>this is the text</c></a>
Phoenix
  • 8,695
  • 16
  • 55
  • 88

2 Answers2

3

Solution #1: A slight improvement to smaccoun's solution that would preserve any attributes on the c element (not necessary for example XML):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="c">
        <xsl:copy-of select="." />
    </xsl:template>
</xsl:stylesheet>

Solution #2 Another alternative that leverages the built-in template rules, which apply-templates for all elements and copy all text():

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!--identity template for the c element, it's decendant nodes, 
        and attributes (which will only get applied from c or 
        descendant elements)-->
    <xsl:template match="@*|c//node()|c">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Solution #3: A modified identity transform:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!--identity template, copies all content by default-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--don't generate content for these matched elements, 
        just apply-templates to it's children-->
    <xsl:template match="a|b">
        <xsl:apply-templates/>
    </xsl:template>     
</xsl:stylesheet>

Solution #4 If you know what you want, just copy it from a match on the root node

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <xsl:copy-of select="a/b/c" />
    </xsl:template>
</xsl:stylesheet>

If you want to simply remove the <b> element from your input, then a modified identity transform should be used with a template matching the <b> element that simply applies templates to it's children.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!--identity template, copies all content by default-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--don't generate content for the <b>, just apply-templates to it's children-->
    <xsl:template match="b">
        <xsl:apply-templates/>
    </xsl:template>     
</xsl:stylesheet>
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
  • +1. Also, identity transform pattern is the name I was thinking of, not 'copy design pattern'. Didn't know that it would copy the attributes as text, good to know! –  Nov 29 '12 at 06:40
  • Mads, can you look at the edit i made. I wanted a to be preserved but b to be removed – Phoenix Nov 29 '12 at 19:03
  • You would want to use Solution #3, just remove `a` from the match criteria, so that it is handled by the generic match on `@*|node()`, which will copy the content. The match on `b` will suppress it's content, but apply templates to it's children, which will also match the generic template that copies to the output. – Mads Hansen Nov 30 '12 at 03:12
1

Apply the template on <c> and then just use a copy design pattern.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match='c'>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
  • 2
    This works for this instance document. However, if `` had attributes, the values would be copied as text content, rather than being preserved. (e.g. `this is the text` would result in `foothis is the text`) – Mads Hansen Nov 29 '12 at 00:51