Peter Stuifzand

Rewrite XML with xmlstarlet

XML Starlet is a program that makes transforming XML documents really simple.

The command that you need to transform an XML document is the following.

xmlstarlet tr [<options>] <xsl-file> {-p|-s <name>=<value>} [ <xml-file-or-uri> ... ]

The XSL file that transforms a document to itself is this. It copies all elements, attributes and texts. We can extend this file to remove, add, or transform elements.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

To remove an element, we match an element and don’t call apply-elements inside it. This example will remove the remove me element.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Remove the element -->
    <xsl:template match="remove-me">
    </xsl:template>
</xsl:stylesheet>

To add an element, we just add the part we would like to add. If it needs to be in a certain place, we can add an extra xsl:template rule. The this-will-get-added element will be inserted after the element element.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

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

        <this-will-get-added></this-will-get-added>
    </xsl:template>
</xsl:stylesheet>

To transform an element we remove xsl:copy and replace it with the elements we need. If we keep the xsl:apply-elements tag in the xsl:template tag, we copy everything inside the element in it’s place.

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- IdentityTransform -->
    <xsl:template match="/ | @* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element">
        <my-new-element>
            <xsl:apply-templates select="@* | node()" />
        </my-new-element>
    </xsl:template>
</xsl:stylesheet>

XSL used in this way becomes quite simple to use. With these three patterns we can extend the identity transformation and get quite a bit of power when we transform XML documents.

© 2023 Peter Stuifzand