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;
}
War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top