Search code examples
htmlxmlxsltparent

XSLT: Move child node after parent node


I'm currently using XSLT to clean and alter some (exported) HTML. Works pretty good so far. ;)

But I need to alter a table so that the tfoot will be copied outside the table.

Input: (exported by Adobe Indesign):

<table>
<thead>
    <tr>
        <td>Stuff</td>
        <td>More Stuff</td>
    </tr>
</thead>
<tfoot>
    <tr>
        <td>Some footer things</td>
        <td>Even more footer</td>
    </tr>
</tfoot>
<tbody>
    <tr>
        <td>Stuff</td>
        <td>More Stuff</td>
    </tr>
</tbody>
</table>

My expected output:

<table>
<thead>
    <tr>
        <td>Stuff</td>
        <td>More Stuff</td>
    </tr>
</thead>
<tbody>
    <tr>
        <td>Stuff</td>
        <td>More Stuff</td>
    </tr>
</tbody>
</table>
<div class="footer">
    Some footer things
    Even more footer
</div>

The first thing I do in my XSL is to copy everything:

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

But what's the next step? Is this even possible with XSLT? Thanks in advance.


Solution

  • Try something like:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="table">
        <xsl:copy>
            <xsl:apply-templates select="thead"/>
            <xsl:apply-templates select="tbody"/>
        </xsl:copy>
        <xsl:apply-templates select="tfoot"/>
    </xsl:template>
    
    <xsl:template match="tfoot">
        <div class="footer">
            <xsl:apply-templates select="tr/td/text()"/>
        </div>
    </xsl:template>
    
    </xsl:stylesheet>
    

    I am not sure how exactly you want to arrange the contents of the footer div; you might want to use xsl:for-each to insert a separator between the text nodes.

    Note also that the result here is not well-formed XML, because it has no single root element.