New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
petergeneric opened this Issue Apr 12, 2013 · 3 comments

Comments

Projects
None yet
2 participants
@petergeneric
Contributor

petergeneric commented Apr 12, 2013

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>
@rolfl

This comment has been minimized.

Show comment
Hide comment
@rolfl

rolfl Apr 12, 2013

Collaborator

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

Collaborator

rolfl commented Apr 12, 2013

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

@petergeneric

This comment has been minimized.

Show comment
Hide comment
@petergeneric

petergeneric Apr 12, 2013

Contributor

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)

Contributor

petergeneric commented Apr 12, 2013

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)

@rolfl

This comment has been minimized.

Show comment
Hide comment
@rolfl

rolfl Apr 12, 2013

Collaborator

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

Collaborator

rolfl commented Apr 12, 2013

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

@rolfl rolfl closed this Apr 12, 2013

petergeneric added a commit to petergeneric/stdlib that referenced this issue May 5, 2015

Remove Base64 (we depend on Java 1.8 so can use the native Base64 imp…
…lementation) and FixedDOMOutputProcessor (only necessary for an old JDOM2 version without the fix for hunterhacker/jdom#115 )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment