Skip to content
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

@petergeneric
Copy link
Contributor

@petergeneric 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
Copy link
Collaborator

@rolfl 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
Copy link
Contributor Author

@petergeneric 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
Copy link
Collaborator

@rolfl 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
…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
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.