سؤال

أقوم بإنشاء برنامج نصي يجب أن يصيب ملفات XML ، بما في ذلك استبدال قائمة العناصر بأخرى. تطبق الوظيفة التالية تصحيحًا (تتضمن قائمة فارغة من العناصر ذات الاسم نفسه) على قائمة العناصر الخاصة بعنصر الأصل بنفس الاسم (ربما أيضًا قائمة فارغة). (هذا ليس سوى جزء صغير من منطق الترقيع).

لماذا ، عندما أقوم بتشغيل الكود ، هل أحصل على الخطأ التالي؟

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)

(تم تصنيف السطر 514 أدناه.) بقدر ما أفهمه ، لقد تحقق للتو من وجود العنصر (لأن Nodelist حي ، سيكون أول إدخاله دائمًا هو المباراة التالية أو الفارغ). ومن المثير للاهتمام أن هذه ليست مشكلة دائمًا.

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();
    }
}

تحرير: لقد استخدمت الوظيفة التالية كبديل ل getElementsByTagName() (انظر الإجابة المقبولة).

/** 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;
}
هل كانت مفيدة؟

المحلول

هذا لأنه عندما تقوم بعمل Parent.RemoveChild (العقدة) ، فإن الوالد ليس بالضرورة أحد الوالدين للعقدة لأن getElementsByTagname () يقوم بالبحث العودية.

نصائح أخرى

ماذا عن

nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved);

parent.removeChild(node) هو رمي not_found_err بسبب node ليس طفل parent. أرى ذلك node يأتي من getElementsByTagName الذي قد لا يكون طفلًا مباشرًا parent. يمكن أن يكون في أي مكان تحت parent.

بناء على التشخيص بواسطة maurice و @fahd ...

لا يمكنك فقط وضع شرط من قبل

parent.removeChild(node);

مثل

if (parent.isSameNode(node.getParentNode()))

بعد ذلك ، لن يؤدي إلا إلى إزالة طفل مباشر للوالد المحدد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top