Вопрос по xml, removechild, java, getelementsbytagname – Почему я не могу удалить дочерний элемент, который я только что нашел? NOT_FOUND_ERR

16

Я строю скрипт, который должен исправлять файлы 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;
}

Ваш Ответ

4   ответа
13

что при выполнении parent.removeChild (node) parent не обязательно является родительским для узла, поскольку getElementsByTagName () выполняет рекурсивный поиск.

Это казалось лучшим решением. Я реализовал функцию возвратаList<Node> так как в моем случае я также не хочу "живое" поведениеNodeList (добавлено в конце моего вопроса, так как я не могу разместить здесь блоки кода). dhardy
Спасибо вам обоим. Есть ли нерекурсивная версия -getChildNodes() и, возможно, реализовать свой собственный поиск по имени? Чем больше я изучаю XML-библиотеку Java, тем меньше я нахожу ее ожидаемой. dhardy
Я думаю, вам придется реализовать свой собственный поиск Maurice Perry
12

как насчет

nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved);
это так, эта строка должна быть на 514 - вы находите узел с помощью getElementsByTagName, вы удаляете его из его родителя с помощью API getParentNode Kalpesh Soni
Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под своим постом. NT3RP
4

parent.removeChild(node) выбрасывает NOT_FOUND_ERR, потому чтоnode не дитяparent, я вижу этоnode происходит отgetElementsByTagName который не может быть непосредственным ребенкомparent, Это может быть где угодно подparent.

0

Не могли бы вы просто поставить условие перед

parent.removeChild(node);

такие как

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

Тогда это только удалило бы прямого потомка данного родителя.

Думаю, это сработает, к сожалению, довольно неэффективно. dhardy

Похожие вопросы