Skip to main content

Tip: Moving DOM nodes

How to avoid Wrong document exceptions

Brett McLaughlin (brett@newInstance.com), Enhydra strategist, Lutris Technologies
Brett McLaughlin (brett@newInstance.com) works as Enhydra strategist at Lutris Technologies and specializes in distributed systems architecture. He is author of Java and XML (O'Reilly). He is involved in technologies such as Java servlets, Enterprise JavaBeans technology, XML, and business-to-business applications. Along with Jason Hunter, he founded the JDOM project, which provides a simple API for manipulating XML from Java applications. He is also an active developer on the Apache Cocoon project and the EJBoss EJB server as well as a co-founder of the Apache Turbine project.

Summary:  This tip takes a look at a common exception that occurs when you attempt to move DOM nodes. Here you'll learn the causes of this exception and, most important, how to avoid it when doing DOM programming. The code listings demonstrate how to move nodes from one document to another, what the code that generates the dreaded Wrong document exception looks like, and how to write correct code that doesn't present this problem. This tip assumes that you already know the basics about how to work with the DOM."

View more content in this series

Date:  01 Mar 2001
Level:  Introductory
Activity:  4037 views

If you've been working with Java and XML for any length of time, you've almost certainly come across a situation in which you either needed or were told to use the DOM, the Document Object Model, from the W3C (see Resources). And if you've taken a step toward using DOM, you've probably also run across the dreaded "" exception when using the DOM. In this tip I'll use an example that moves DOM nodes to explain exactly what causes that rather annoying error. I'll also show you how to avoid running into this exception in your future DOM programming.

For a (somewhat cheesy) example, look at two XML documents in the first two listings. Listing 1 shows test1.xml, a list of Playstation 2 (PS2) games in a store's current inventory.

<?xml version="1.0"?>

<videoGames>
  <game system="PS2">
    <title>Madden 2001</title>
    <maxPlayers>8</maxPlayers>
  </game>

  <game system="PS2">
    <title>SSX</title>
    <maxPlayers>2</maxPlayers>
  </game>

  <game system="PS2">
    <title>NHL 2001</title>
    <maxPlayers>8</maxPlayers>
  </game>
</videoGames>

The second example, test2.xml, displays the new game shipments that have arrived at the store. It shows a new PS2 game, which is represented in Listing 2:

<?xml version="1.0"?>

<newInventory>
  <game system="PS2">
    <title>DOA2: Hardcore</title>
    <maxPlayers>4</maxPlayers>
  </game>
</newInventory>

The point of this exercise is to take the game from the new inventory (represented in DOM by the org.w3c.dom.Node interface) and move it from test2.xml into the current inventory listing in test1.xml. To do this, you pull up the DOM API documentation and your parser (I'm using Xerces for the example) and code up a little program like the one in Listing 3:

import org.apache.xerces.parsers.DOMParser;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class MoveNode {

    public static void main(String[] args) {
        try {
            DOMParser parser = new DOMParser();

           // Create the first document
            parser.parse(new InputSource(args[0]));
            Document doc1 = parser.getDocument();

           // Create the second document
            parser.parse(new InputSource(args[1]));
            Document doc2 = parser.getDocument();

             // Get root of first document
            Element firstRoot = doc1.getDocumentElement();

             // Get Node to move
            Element secondRoot = doc2.getDocumentElement();
            NodeList kids = secondRoot.getElementsByTagName("game");
            Element oneToMove = (Element)kids.item(0);

             // Add to first document
            firstRoot.appendChild(oneToMove);

        } catch (Exception e) {
             e.printStackTrace();
        }
    }

}

Looks pretty good, right? The code compiles (with xerces.jar in the classpath, of course). It creates DOM trees out of each XML document. It gets the root element from the first document. It gets the element to move from the second, then it moves that element beneath the first document's root element. Simple enough... until you run the code, which is when you get the dreaded Wrong document exception! Listing 4 shows this in action:

/usr/local/projects/tips>java MoveNode
                       file:///usr/local/projects/tips/test1.xml
                       file:///usr/local/projects/tips/test2.xml

org.apache.xerces.dom.DOMExceptionImpl: DOM005 Wrong document
 at org.apache.xerces.dom.
ChildAndParentNode.internalInsertBefore(ChildAndParentNode.java:314)
 at org.apache.xerces.dom.
ChildAndParentNode.insertBefore(ChildAndParentNode.java:296)
 at org.apache.xerces.dom.NodeImpl.appendChild(NodeImpl.java:213)
 at MoveNode.main(MoveNode.java:30)

If you aren't using Xerces, the exact message you get may be different from this, but the idea is the same: Wrong document. What the heck does that mean? Well, in DOM, the Document object actually is a factory. As a result, it has the job of creating implementations of the various DOM interfaces when requested, such as implementations of Node, Element, Attr, and so on. When you add a Node to a document, that document must know how to work with the new Node implementation.

In a nutshell, working with DOM requires that any Node always be tied to a specific document, which is the factory, remember? Unfortunately, DOM implementations do not, at least in any of the products I've used, automatically take care of dealing with this little detail. So although the code in Listing 3 added the child to the first document's root element (with the appendChild() method), it didn't let the first document know enough about the new node it needed to deal with. Seems a little strange, huh? Yeah, I know, but all APIs have quirks, and this is one fairly common to factory-based APIs. In any case, making the code work takes a fairly simple change. Check out Listing 5, which shows corrected code:

import org.apache.xerces.parsers.DOMParser;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class MoveNode {

    public static void main(String[] args) {
        try {
            DOMParser parser = new DOMParser();

            // Create the first document
            parser.parse(new InputSource(args[0]));
            Document doc1 = parser.getDocument();

            // Create the second document
            parser.parse(new InputSource(args[1]));
            Document doc2 = parser.getDocument();

            // Get root of first document
            Element firstRoot = doc1.getDocumentElement();

            // Get Node to move
            Element secondRoot = doc2.getDocumentElement();
            NodeList kids = secondRoot.getElementsByTagName("game");
            Element oneToMove = (Element)kids.item(0);

            // Add to first document

            Node newOneToMove = doc1.importNode(oneToMove, true);
            firstRoot.appendChild(newOneToMove);

        } catch (Exception e) {
             e.printStackTrace();
        }

    }
}

Listing 5 creates a new Node that is suitable for use in the first document. Incidentally, this also preserves the use of the original node (oneToMove) for use in the second document. Once the node has been imported, it can be appended as in the first example. So, moving nodes between DOM trees actually takes two method invocations, rather than just one. Remember that, and the Wrong document error message that your friends are getting will bother you no more! Go forth and use the DOM wisely.


Resources

About the author

Brett McLaughlin (brett@newInstance.com) works as Enhydra strategist at Lutris Technologies and specializes in distributed systems architecture. He is author of Java and XML (O'Reilly). He is involved in technologies such as Java servlets, Enterprise JavaBeans technology, XML, and business-to-business applications. Along with Jason Hunter, he founded the JDOM project, which provides a simple API for manipulating XML from Java applications. He is also an active developer on the Apache Cocoon project and the EJBoss EJB server as well as a co-founder of the Apache Turbine project.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=11978
ArticleTitle=Tip: Moving DOM nodes
publish-date=03012001
author1-email=brett@newInstance.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers