I'm building a script which has to patch XML files, including replacing one list of elements with another. The following function applies a patch (involving a possibly empty list of elements with the same name) onto a parent Element's list of elements by the same name (also possibly an empty list). (This is only a small part of the patching logic).
Why, when I run the code, do I get the following error?
org.w3c.dom.DOMException: NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist.
at com.sun.org.apache.xerces.internal.dom.ParentNode.internalRemoveChild(ParentNode.java:503)
at com.sun.org.apache.xerces.internal.dom.ParentNode.removeChild(ParentNode.java:484)
at CombineSweeps$PTReplaceNodeList.apply(CombineSweeps.java:514)
(Line 514 is labelled below.) As far as I understand it, I've just verified that the element exists (because NodeList is live, its first entry will always be the next match or null). Interestingly, this isn't always a problem.
private static class PTReplaceNodeList extends PTBase {
private final String name;
private final String nextElement;
private final List<Node> childList;
...
int apply(Document document, Node parent, Node node_unused) {
NodeList nodes;
// A marker for where to insert our nodes.
// We make a guess using nextElement (if null, means at end).
Node refNode = null;
if (parent instanceof Document) { // root element
Document parDoc = (Document) parent;
nodes = parDoc.getElementsByTagName(name);
if (nextElement != null) {
refNode = parDoc.getElementsByTagName(nextElement).item(0);
}
} else {
Element parElt = (Element) parent;
nodes = parElt.getElementsByTagName(name);
if (nextElement != null) {
refNode = parElt.getElementsByTagName(nextElement).item(0);
}
}
while (true) {
// iterate through the list of nodes
Node node = nodes.item(0);
if (node == null) {
break;
}
// Reliable guess: insert before node following last in list
refNode = node.getNextSibling();
parent.removeChild(node); // line 514
}
for (Node child : childList) {
Node imported = document.importNode(child, true);
parent.insertBefore(imported, refNode);
}
return childList.size();
}
}
Edit: I used the following function as a replacement for getElementsByTagName()
(see accepted answer).
/** Returns all direct children of node with name name.
*
* Note: not the same as getElementsByTagName(), which finds all descendants. */
static List<Node> getChildNodes( Node node, String name ){
ArrayList<Node> r = new ArrayList<Node>();
NodeList children = node.getChildNodes();
int l = children.getLength();
for( int i = 0; i < l; ++i ){
if( name.equals( children.item(i).getNodeName() ) )
r.add( children.item(i) );
}
return r;
}
Child nodes can be removed from a parent with removeChild(), and a node itself can be removed with remove(). Another method to remove all child of a node is to set it's innerHTML=”” property, it is an empty string which produces the same output.
removeChild() The removeChild() method of the Node interface removes a child node from the DOM and returns the removed node. Note: As long as a reference is kept on the removed child, it still exists in memory, but is no longer part of the DOM. It can still be reused later in the code.
how about
nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved);
This is because when you are doing parent.removeChild(node), parent is not necessarily the parent of the node because getElementsByTagName() is doing a recursive search.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With