2010-09-15 16 views
15

Estoy construyendo una secuencia de comandos que tiene que parchear archivos XML, incluida la sustitución de una lista de elementos por otra. La siguiente función aplica un parche (que involucra una lista posiblemente vacía de elementos con el mismo nombre) en la lista de elementos de un elemento padre con el mismo nombre (posiblemente también una lista vacía). (Esto es solo una pequeña parte de la lógica de parchado).¿Por qué no puedo eliminar un elemento secundario que acabo de encontrar? NOT_FOUND_ERR

¿Por qué, cuando ejecuto el código, obtengo el siguiente error?

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) 

(línea 514 se etiqueta a continuación.) Por lo que yo entiendo, sólo he verificado que existe el elemento (NodeList porque es en vivo, su primera entrada siempre será el próximo partido o nulo). Curiosamente, esto no siempre es un problema.

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: utiliza la siguiente función como un reemplazo para getElementsByTagName() (ver respuesta aceptada).

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

Respuesta

12

Esto es porque cuando usted está haciendo parent.removeChild (nodo), el padre no es necesariamente el padre del nodo debido getElementsByTagName() está haciendo una búsqueda recursiva.

+0

Gracias a los dos. ¿Hay alguna versión no recursiva, 'getChildNodes()' e implementar mi propia búsqueda por nombre, tal vez? Cuanto más estoy aprendiendo acerca de la biblioteca XML de Java, menos estoy descubriendo que hace lo que esperaba. – dhardy

+0

Supongo que tendrá que implementar su propia búsqueda –

+0

Esta parece ser la mejor solución. Implementé una función devolviendo 'List ' ya que en mi caso tampoco quiero realmente el comportamiento "en vivo" de 'NodeList' (agregado al final de mi pregunta ya que no puedo publicar bloques de código aquí). – dhardy

4

parent.removeChild(node) está lanzando un NOT_FOUND_ERR porque node no es un hijo de parent. Veo que node viene de getElementsByTagName, que podría no ser un hijo inmediato de parent. Podría estar en cualquier parte bajo parent.

0

Sobre la base del diagnóstico por @Maurice y @fahd ...

no puedes poner una condición antes de

parent.removeChild(node); 

como

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

entonces este únicamente eliminar un hijo directo del padre dado.

+0

Supongo que funcionaría, desafortunadamente de una manera bastante ineficiente. – dhardy

11

¿qué tal

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

Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar aclaraciones de un autor, deje un comentario debajo de su publicación. – NT3RP

+0

, esta línea debe estar en 514; encuentra un nodo usando getElementsByTagName, lo quita de su padre usando la API getParentNode –

Cuestiones relacionadas