Tuesday, November 6, 2012

Remove all namespaces from XML using XSLT

Sometimes, for obscurs reasons, you needs to remove all namespaces of an XML source (DOM, Stream, File, ...). Thanks to the standard javax.xml.transform library, you can apply XSLT transformations to XML to easily remove all namespaces that bother you! All the source code is here on Github.

Templating rules

The first thing to do is to define the file remove-namespace.xslt containing templating rules needed to remove all namespaces from the XML source. See below the 3 transformations to apply :

The first templating rule to apply remove namespaces prefixing elements.

    <!-- copy elements -->
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

The second templating rule is needed to copy attributes.

    <!-- copy attributes -->
    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

The third rule just copy all the rest of the node processed.

    <!-- copy the rest of the nodes -->
    <xsl:template match="comment() | text() | processing-instruction()">
        <xsl:copy/>
    </xsl:template>

Java Transformation API

The main job is done by defining templating rules. Now you just need to use the Java transformation API, see below :

    public void removeNamespace(Source xmlSource, Result xmlOutput) throws TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        InputStream xslt = XmlUtils.class.getResourceAsStream("/remove-namespace.xslt");
        Transformer transformer = factory.newTransformer(new StreamSource(xslt));
        transformer.transform(xmlSource, xmlOutput);
    }

XML Unit Testing

Of course you need a unit test to verify that all namespaces are really removed. There is the XML Unit OpenSource project that could do the job by comparing strictly 2 XML files.
    @Test
    public void testRemoveNamespace() throws IOException, TransformerException, SAXException {
        InputStream xmlSource = XmlUtilsTest.class.getResourceAsStream("with-namespace.xml");
        InputStream xmlExpected = XmlUtilsTest.class.getResourceAsStream("without-namespace.xml");
        StreamSource source = new StreamSource();
        StreamResult result = new StreamResult(new StringWriter());
        XmlUtils.removeNamespace(source, result);
        Diff diff = new Diff(inputStreamToString(xmlExpected), result.getWriter().toString());
        DetailedDiff detailedDiff = new DetailedDiff(diff);
        List<Difference> diffs = detailedDiff.getAllDifferences();
        assertNotNull(diffs);
        assertEquals(0, diffs.size());
    }

See also :

2 comments:

  1. Does the xslt transformation works fine with large XML files ?

    ReplyDelete
  2. I don't know you should try and measure it, sorry.

    ReplyDelete