TheUltimateHack
TheUltimateHack

Reputation: 137

Question regarding Java upgrade from 11 to 17 and its effect on XML parsing using Java DOM document

Considering the following XML

<TestFile>
    <TestHeader>
        <FileVersion>2.00</FileVersion>
        <FileCountry>GB</FileCountry>
        <FileRegion>LND</FileRegion>
    </TestHeader>
</TestFile>

In the past I have parsed using Java DOM to set the default namespace like this

MyDoc.getDocumentElement().setAttribute("xmlns", this.NameSpaceAsString);

In earlier versions of Java 8, this produced a proper XML like this

<TestFile xmlns="mynamespace.com">
<TestHeader>
    <FileVersion>2.00</FileVersion>
    <FileCountry>GB</FileCountry>
    <FileRegion>LND</FileRegion>
</TestHeader>

However, with an upgrade to Java 11, Im now getting 2 default namespaces on the top 2 nodes with one of them being empty like this

<TestFile xmlns="mynamespace.com">
<TestHeader xmlns=" ">
    <FileVersion>2.00</FileVersion>
    <FileCountry>GB</FileCountry>
    <FileRegion>LND</FileRegion>
</TestHeader>

Im not sure what changed that would cause getDocumentElement to find 2 nodes or setAttribute to set in 2 places.

Upvotes: -1

Views: 75

Answers (1)

forty-two
forty-two

Reputation: 12817

Given this code:

    public static void main(String[] args) throws Exception {
        System.out.println("JVM version: " + System.getProperty("java.version"));
        Document d = DocumentBuilderFactory
                .newInstance()
                .newDocumentBuilder()
                .parse(new File("data.xml"));
        d.getDocumentElement().setAttribute("xmlns", "xyzzy");
        TransformerFactory
            .newInstance()
            .newTransformer()
            .transform(new DOMSource(d), new StreamResult(System.out));

    }

The output for four different java versions is:

JVM version: 1.7.0_352
<?xml version="1.0" encoding="UTF-8" standalone="no"?><TestFile xmlns="xyzzy">
    <TestHeader>
        <FileVersion>2.00</FileVersion>
        <FileCountry>GB</FileCountry>
        <FileRegion>LND</FileRegion>
    </TestHeader>
</TestFile

JVM version: 1.8.0_282b08-internal
<?xml version="1.0" encoding="UTF-8" standalone="no"?><TestFile xmlns="xyzzy">
    <TestHeader>
        <FileVersion>2.00</FileVersion>
        <FileCountry>GB</FileCountry>
        <FileRegion>LND</FileRegion>
    </TestHeader>
</TestFile>

JVM version: 11.0.25
<?xml version="1.0" encoding="UTF-8" standalone="no"?><TestFile xmlns="xyzzy">
    <TestHeader>
        <FileVersion>2.00</FileVersion>
        <FileCountry>GB</FileCountry>
        <FileRegion>LND</FileRegion>
    </TestHeader>
</TestFile>

JVM version: 23.0.1
<?xml version="1.0" encoding="UTF-8" standalone="no"?><TestFile xmlns="xyzzy">
    <TestHeader>
        <FileVersion>2.00</FileVersion>
        <FileCountry>GB</FileCountry>
        <FileRegion>LND</FileRegion>
    </TestHeader>
</TestFile>

Note that it is always a bad idea managing namespaces with a namespace unaware XML processor.

Update:

The "correct" way to change the namespace of every Element in the document would be something like this:

        DocumentBuilderFactory f = DocumentBuilderFactory.newDefaultInstance();
        f.setNamespaceAware(true);
        Document d = f
                .newDocumentBuilder()
                .parse(new File("data.xml"));

        TreeWalker tw = ((DocumentTraversal)d).createTreeWalker(d, NodeFilter.SHOW_ELEMENT, null, false);
        Node node;
        while((node = tw.nextNode()) != null) {
            if (node instanceof Element e) {
                d.renameNode(e, "xyzzy", e.getTagName());
            }
        }

        TransformerFactory
            .newInstance()
            .newTransformer()
            .transform(new DOMSource(d), new StreamResult(System.out));

This does not involve "cheating" by adding an "xmlns" attribute to an otherwise namespace unaware document

Upvotes: 2

Related Questions