Warum kann ich nicht ein untergeordnetes Element entferne ich habe gerade gefunden? NOT_FOUND_ERR
-
03-10-2019 - |
Frage
Ich baue ein Skript, die XML-Dateien patchen, darunter eine Liste von Elementen mit einem anderen zu ersetzen. Die folgende Funktion gilt einen Patch auf ein übergeordnetes Elemente der Liste von Elementen mit dem gleichen Namen (eine möglicherweise leere Liste von Elementen mit dem gleichen Namen beteiligt) (möglicherweise auch eine leere Liste). (Dies ist nur ein kleiner Teil der Patching-Logik).
Warum, wenn ich den Code ausführen, bekomme ich folgende Fehlermeldung?
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)
(Linie 514 unten markiert ist.) Soweit ich es verstehe, habe ich gerade festgestellt, dass das Element vorhanden ist (weil NodeList Live ist, sein erster Eintrag wird immer das nächste Spiel oder null sein). Interessanterweise ist dies nicht immer ein 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:. Ich habe die folgende Funktion als Ersatz für getElementsByTagName()
(siehe akzeptierte Antwort)
/** 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;
}
Lösung
Dies liegt daran, wenn Sie parent.removeChild (Knoten) tun, Eltern nicht unbedingt die Eltern des Knotens ist, weil getElementsByTagName () eine rekursive Suche tut.
Andere Tipps
, wie etwa
nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved);
parent.removeChild(node)
wirft einen NOT_FOUND_ERR weil node
kein Kind von parent
ist. Ich sehe, dass node
von getElementsByTagName
kommt, die kein unmittelbares Kind von parent
sein könnte. Es könnte überall unter parent
sein.
Auf der Grundlage der Diagnose von @Maurice und @fahd ...
Sie können nicht nur eine Bedingung gestellt, bevor
parent.removeChild(node);
wie
if (parent.isSameNode(node.getParentNode()))
Dann wäre es nur ein direktes Kind des gegebenen Elternteil entfernen.