So, my project does a lot of in-memory xml manipulations. This means we add, remove and even move xml nodes within a document. We chose dom4j because it has the fastest writes, edits and xpath (using jaxen) among dom4j, jdom, xerces+xalan and xerces+jaxen.

Anyway, I started running into some strange errors when I tried to move an element within a document. A move consists of detaching an element from it's parent and assigning it to a new parent either after or before a particular node.

Dom4j lets you position new nodes by providing a List interface to the underlying structure. So you get a particular parent element and then get the list using either Branch.content() or Element.elements(). content() gives you all of the child nodes, elements() gives you only the child nodes that are elements. Now that you have a list you can add an element using the standard List methods add(Object) add(int,Object).

The problem arose when on this line of code:

parentElements.add(newPosition, newNode.detach());

 

I started getting this exception:

java.lang.IndexOutOfBoundsException: Index: -1, Size: 12
at java.util.ArrayList.add(ArrayList.java:367)
at org.dom4j.tree.AbstractElement.addNewNode(AbstractElement.java:1552)
at org.dom4j.tree.AbstractElement.addNode(AbstractElement.java:1536)
at org.dom4j.tree.BackedList.add(BackedList.java:79)

 

This was pretty confusing because while debugging, parentElements.size() was equal to 6 and newPosition was equal to 2. This made the error message a bit confusing.

I ended up digging into the dom4j source and found out that whenever you call detach(), it changes the parent node's structure and empties out the element list. This isn't really intuitive, but makes sense. As if you try to move an element within a parent, it could cause problems. This sucks because if you try to move an element earlier in the parent, the detach shouldn't affect the operation.

But the good news is that when I moved the call to elements() after detach(), I stopped getting the error. I guess I'll add a new item to dom4j's tracker and hope it gets fixed in a later version.