XML fix namespace declaration

让人想犯罪 __ 提交于 2019-12-23 03:48:08


I am trying to detetct/work around this bug in RSS elements. That means I have to find a wrong namespace-declaration and change its value to the correct namespace. E.g:


must be:


How can I achive that given a org.w3c.Document?

I meanwile found out how to get all elements of a certain namespace:

        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();
        XPathExpression expr = xpath.compile("//*[namespace-uri()='http://search.yahoo.com/mrss']");

        Object result = expr.evaluate(d, XPathConstants.NODESET);
        if (result != null) {
            NodeList nodes = (NodeList) result;
            for(int node=0;node<nodes.getLength();node++)
                Node n = nodes.item(node);
                this.log.warn("Found old mediaRSS namespace declaration: "+n.getTextContent());


So now I have to figure out how to change the namespace of a Node via JAXP.


You could probably do it with XSLT, with a rule like this:

<xsl:template match="media:*">
   <xsl:element name="local-name()" namespace="http://search.yahoo.com/mrss/">
      <xsl:apply-templates match="node()|@*"/>

where media is bound to "http://search.yahoo.com/mrss".

You may have to tweak the syntax a little, as I'm writing this without the help of a compiler. Also, what you'll get is probably not extremely nicely formatted (namespace declarations on many elements), but it should be locically correct.


Just for the sake of completeness:

Java Code:

Document d = out.outputW3CDom(converted);
            DOMSource oldDocument = new DOMSource(d);
            DOMResult newDocument = new DOMResult();
            TransformerFactory tf = TransformerFactory.newInstance();
            StreamSource xsltsource = new StreamSource(
            Transformer transformer = tf.newTransformer(xsltsource);
            transformer.transform(oldDocument, newDocument);

private InputStream getStream(String fileName) {
    InputStream xslStream = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream("/" + fileName);
    if (xslStream == null) {
        xslStream = Thread.currentThread().getContextClassLoader()      .getResourceAsStream(fileName);
        return xslStream;


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    <!--identity transform that will copy matched node/attribute to the output and apply templates for it's children and attached attributes-->
    <xsl:template match="node()|@*">
            <xsl:apply-templates select="@*|*|text()" />

    <!--Specialized template to match on elements with the incorrect namespace and generate a new element-->
    <xsl:template match="//*[namespace-uri()='http://search.yahoo.com/mrss']">
        <xsl:element name="{local-name()}" namespace="http://search.yahoo.com/mrss/" >
            <xsl:apply-templates select="@*|*|text()" />

Special thanks to Mads Hansen for his help with the XSLT.