2010-09-15 71 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

相關問題