Skip to content

AbstractDOMOutputProcessor doesn't explicitly set namespace of xmlns attributes #115

Closed

Description

@petergeneric

Hello,

The default implementation of DOMOutputProcessor generates xmlns attributes without setting the namespace. On the JAXP in Oracle Java 1.7 this means the generated Attrs have a null Namespace URI. This is causing us problems when serialising these Elements as part of a JAXB object (using EclipseLink MOXy - the Metro implementation is able to cope with it).

I'm not entirely sure if this is strictly a bug in JDOM or if the fault lies with JAXP for not inferring the Namespace URI on an element prefixed with "xmlns" - but it does mean the Documents coming from DOMOutputter don't look the same as a document coming from the built-in DocumentBuilderFactory.

Here's a JUnit test to reproduce the issue.

import org.jdom2.Element;
import org.jdom2.JDOMConstants;
import org.jdom2.input.DOMBuilder;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.DOMOutputter;
import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;

import static org.junit.Assert.assertEquals;

public class DOMOutputterNamespaceTest
{
    /**
     * The XML document to test - this document
     */
    private static final String XML = "<el xmlns:test=\"urn:test\" />";


    /**
     * Parse the XML using DOM
     *
     * @throws Exception
     */
    @Test
    public void testDocumentBuilderSource() throws Exception
    {
        org.w3c.dom.Element element = parseDOM(XML);

        final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();

        assertEquals("DocumentBuilder output", JDOMConstants.NS_URI_XMLNS, namespace);
    }


    /**
     * Parse the XML using JDOM, convert to DOM
     *
     * @throws Exception
     */
    @Test
    public void testJdomToDom() throws Exception
    {
        org.w3c.dom.Element element = jdomToDom(parseJDOM(XML)); // load JDOM and convert to DOM

        final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();

        assertEquals("SAXBuilder->DOMOutputter output", JDOMConstants.NS_URI_XMLNS, namespace);
    }


    /**
     * Parse the XML using DOM, then convert to JDOM and then finally back to DOM
     *
     * @throws Exception
     */

    @Test
    public void testDomToJdomToDom() throws Exception
    {
        org.w3c.dom.Element element = jdomToDom(domToJdom(parseDOM(XML))); // load DOM, convert to JDOM and back to DOM

        final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();

        assertEquals("DocumentBuilder->DOMBuilder->DOMOutputter output", JDOMConstants.NS_URI_XMLNS, namespace);
    }


    private Element parseJDOM(String xml) throws Exception
    {
        final StringReader src = new StringReader(xml);

        return new SAXBuilder().build(src).getRootElement();
    }


    private org.w3c.dom.Element parseDOM(String xml) throws Exception
    {
        InputSource src = new InputSource(new StringReader(xml));

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);

        DocumentBuilder documentBuilder = factory.newDocumentBuilder();

        Document result = documentBuilder.parse(src);

        return result.getDocumentElement();
    }


    /**
     * Converts a JDOM Element to a DOM Element
     *
     * @param element
     *
     * @return
     *
     * @throws Exception
     */
    private org.w3c.dom.Element jdomToDom(org.jdom2.Element element) throws Exception
    {
        return new DOMOutputter().output(element);
    }


    /**
     * Converts a DOM Element to a JDOM Element
     *
     * @param element
     *
     * @return
     *
     * @throws Exception
     */
    private org.jdom2.Element domToJdom(org.w3c.dom.Element element) throws Exception
    {
        final DOMBuilder builder = new DOMBuilder();

        return builder.build(element);
    }
}

On our machines (Oracle Java 1.7, JDOM 2.0.4) the output is as follows:

testDocumentBuilderSource: pass
testJdomToDom: fail
    java.lang.AssertionError: SAXBuilder->DOMOutputter output expected:<http://www.w3.org/2000/xmlns/> but was:<null>
testDomToJdomToDom: fail
    java.lang.AssertionError: DocumentBuilder->DOMBuilder->DOMOutputter output expected:<http://www.w3.org/2000/xmlns/> but was:<null>

Activity

  1. rolfl commented on Apr 12, 2013

    @rolfl
    Collaborator

    Well, that's a comprehensive issue report, and a suprising problem. Thanks. I will look in to it shortly.

  2. petergeneric commented on Apr 12, 2013

    @petergeneric
    ContributorAuthor

    I've got a patch to AbstractDOMOutputProcessor that should work at petergeneric@c27a4fc and a unit test as part of petergeneric@2c32cc5 (it doesn't use the same structure as the other jdom unit tests though - added it in a separate commit for clarity)

  3. rolfl commented on Apr 12, 2013

    @rolfl
    Collaborator

    I pulled your fixes right in - b174b37 and 25153ea . Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions