xsltserializationxslt-3.0xpath-3.0

XPath 3.0 Serialize without Namespaces in Scope


While answering this question, it occurred to me that I know how to use the XSLT 3.0 (XPath 3.0) serialize() function, but that I do not know how to avoid serialization of namespaces that are in scope. Here is a minimal example:

XML Input

<?xml version="1.0" encoding="UTF-8" ?>
<ci:cichlids xmlns:ci="http://www.cichlids.com">
    <cichlid id="1">
        <name>Zeus</name>
        <color>gold</color>
        <teeth>molariform</teeth>
        <breeding-type>lekking</breeding-type>
    </cichlid>
</ci:cichlids>

XSLT 3.0 Stylesheet

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization"
    xmlns:ci="http://www.cichlids.com">

    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

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

    <xsl:template match="/ci:cichlids/cichlid">
        <xsl:variable name="serial-params">
            <output:serialization-parameters>
                <output:omit-xml-declaration value="yes"/>
            </output:serialization-parameters>
        </xsl:variable>
        <xsl:value-of select="serialize(., $serial-params/*)"/>
    </xsl:template>

</xsl:stylesheet>

Actual Output

<?xml version="1.0" encoding="UTF-8"?>
<ci:cichlids xmlns:ci="http://www.cichlids.com">
    &lt;cichlid xmlns:ci="http://www.cichlids.com" id="1"&gt;
        &lt;name&gt;Zeus&lt;/name&gt;
        &lt;color&gt;gold&lt;/color&gt;
        &lt;teeth&gt;molariform&lt;/teeth&gt;
        &lt;breeding-type&gt;lekking&lt;/breeding-type&gt;
    &lt;/cichlid&gt;
</ci:cichlids>

The serialization process included the namespace declaration that is in scope for the cichlid element, although it is not used on this element. I would like to remove this declaration and make the output look like

Expected Output

<?xml version="1.0" encoding="UTF-8"?>
<ci:cichlids xmlns:ci="http://www.cichlids.com">
    &lt;cichlid id="1"&gt;
        &lt;name&gt;Zeus&lt;/name&gt;
        &lt;color&gt;gold&lt;/color&gt;
        &lt;teeth&gt;molariform&lt;/teeth&gt;
        &lt;breeding-type&gt;lekking&lt;/breeding-type&gt;
    &lt;/cichlid&gt;
</ci:cichlids>

I know how to modify the cichlid element, removing the namespaces in scope, and serialize this modified element instead. But this seems a rather cumbersome solution. My question is:

What is a canonical way to serialize an XML element using the serialize() function without also serializing unused namespace declarations that are in scope?


Testing with Saxon-EE 9.6.0.7 from within Oxygen.


Solution

  • Serialization will always give you a faithful representation of the data model that you are serializing. If you want to modify the data model, that's called transformation. Run a transformation to remove the unwanted namespaces, then serialize the result.