Perché non è possibile rimuovere un elemento figlio che ho appena trovato? NOT_FOUND_ERR
-
03-10-2019 - |
Domanda
Sto costruendo uno script che deve rattoppare i file XML, tra cui la sostituzione di una lista di elementi con un altro. La seguente funzione applica una patch (che coinvolge una lista vuota di elementi con lo stesso nome) sulla lista di elementi genitore dell'Elemento con lo stesso nome (eventualmente anche un elenco vuoto). (Questa è solo una piccola parte della logica patch).
Perché, quando si esegue il codice, ottengo il seguente errore?
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)
(linea 514 è etichettato sotto.) Per quanto riguarda ho capito, ho appena verificato che l'elemento esiste (perché NodeList è vivo, il suo primo ingresso sarà sempre la prossima partita o null). È interessante notare che questo non è sempre un problema.
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();
}
}
Modifica:. Ho usato la seguente funzione in sostituzione del getElementsByTagName()
(vedi risposta accettata)
/** 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;
}
Soluzione
Questo perché quando si sta facendo parent.removeChild (nodo), genitore non è necessariamente il genitore del nodo perché getElementsByTagName () sta facendo una ricerca ricorsiva.
Altri suggerimenti
come su
nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved);
parent.removeChild(node)
sta gettando un NOT_FOUND_ERR perché node
non è un bambino di parent
. Vedo che node
viene da getElementsByTagName
che potrebbe non essere un figlio diretto di parent
. Potrebbe essere ovunque sotto parent
.
Sulla base della diagnosi @Maurice e @fahd ...
Non puoi semplicemente mettere una condizione prima di
parent.removeChild(node);
come
if (parent.isSameNode(node.getParentNode()))
Poi sarebbe rimuovere solo un figlio diretto del genitore data.