2010-09-15 95 views
15

我正在构建一个脚本,它必须修补XML文件,包括用另一个元素替换一个元素列表。以下函数通过相同的名称(也可能是一个空列表)将一个补丁(涉及一个可能为空的元素名称相同的列表)应用到父元素的元素列表中。 (这只是修补逻辑的一小部分)。为什么我不能删除刚发现的子元素? NOT_FOUND_ERR

为什么当我运行代码时,是否会出现以下错误?

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线如下标记)。据我了解,我只是证实该元件存在(因为节点列表是活的,它的第一个条目将永远是下一场比赛或空)。有趣的是,这并不总是一个问题。

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

回答

12

这是因为当你在做parent.removeChild(节点),父母不一定是节点的getElementsByTagName因为()是做递归搜索父。

+0

感谢你们俩。是否有一个非递归版本 - “getChildNodes()'并实现我自己的名称搜索?也许?我对java的XML库了解得越多,我发现它就越不像我期望的那样。 – dhardy 2010-09-15 19:04:17

+0

我想你将不得不实施自己的搜索 – 2010-09-15 19:21:32

+0

这似乎是最好的解决方案。我实现了一个返回'List '的函数,因为在我的情况下,我也并不真的希望NodeList的“实时”行为(在我的问题结尾添加,因为我无法在此处发布代码块)。 – dhardy 2010-09-16 08:20:25

4

parent.removeChild(node)正在丢一个NOT_FOUND_ERR,因为node不是parent的孩子。我看到node来自getElementsByTagName,它可能不是parent的直系子女。它可能在parent之下的任何地方。

0

大厦诊断由@Maurice和@fahd ...

你就不能放的条件之前

parent.removeChild(node); 

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

话,那就只删除给定父母的直接子女。

+0

我想这会奏效 - 不幸的是效率很低。 – dhardy 2010-09-16 08:14:26

11

怎么样

nodeToBeRemoved.getParentNode().removeChild(nodeToBeRemoved); 
+0

这不提供问题的答案。要批评或要求作者澄清,请在其帖子下方留言。 – NT3RP 2013-09-25 21:01:32

+0

它的作用是,这一行需要在514处 - 通过使用getElementsByTagName找到一个节点,使用getParentNode API从它的父节点中删除它 – 2013-09-26 15:45:26

相关问题