2010-08-04 16 views
8

Dado el siguiente archivo XML:Java DOM - Inserción de un elemento, después de otra

<?xml version="1.0" encoding="UTF-8"?> 
<process 
    name="TestSVG2" 
    xmlns="http://www.example.org" 
    targetNamespace="http://www.example.org" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <sequence> 
     <receive name="Receive1" createInstance="yes"/> 
     <assign name="Assign1"/> 
     <invoke name="Invoke1"/> 
     <assign name="Assign2"/> 
     <reply name="Reply1"/> 
    </sequence> 
</process> 

Quiero añadir un nuevo elemento en el interior del <sequence></sequence>después de un elemento de cierta preexistente. Por ejemplo, si quiero añadir el nodo después de "Assign1", el nuevo XML debe desea:

<sequence> 
     <receive name="Receive1" createInstance="yes"/> 
     <assign name="Assign1"/> 
     <newtype name="NewNode"/> 
     <invoke name="Invoke1"/> 
     <assign name="Assign2"/> 
     <reply name="Reply1"/> 
    </sequence> 

que tengo que hacer esto mediante el uso de Java DOM, en una función. La firma de la función debe desea:

public void addActionDom(String name, String stepType, String stepName) 

Donde:

  • name es el elemento pre-existente, después de lo cual se hará la inserción;
  • stepType es el tipo de elemento insertado;
  • stepName es el atributo de nombre del elemento recién insertado.

Actualmente me falta experiencia con JDOM, o cualquier otra biblioteca XML de Java. ¿Puedes dar un código de muestra o dirigirme a un tutorial donde se realiza una inserción después de que se haya determinado un elemento determinado?

Este es el código que tengo hasta ahora:

public void addActionDom(String name, String stepType, String stepName) { 
     File xmlFile = new File(path + "/resources/" + BPELFilename); 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     DocumentBuilder db; 
     try { 
      /* Load XML */ 
      db = dbf.newDocumentBuilder(); 
      Document doc = db.parse(xmlFile); 
      doc.getDocumentElement().normalize(); 

      /* Iterate throughout the type tags and delete */ 
      for (String cTag : typeTags) { 
       NodeList cnl = doc.getElementsByTagName(cTag); 
       for (int i = 0; i < cnl.getLength(); ++i) { 
        Node cnode = cnl.item(i); 
        if (cnode.getNodeType() == Node.ELEMENT_NODE) { 
         Element elem = (Element)cnode; // 'elem' Element after which the insertion should be made 
         if (elem.getAttribute("name").equals(name)) { 
          Element newElement = doc.createElement(stepType); // Element to be inserted 
          newElement.setAttribute("name", stepName); 
          // CODE HERE 
         } 
        } 
       } 
      } 

      /* Save the editing */ 
      Transformer transformer = 
       TransformerFactory.newInstance().newTransformer(); 
      StreamResult result = 
       new StreamResult(new FileOutputStream(path + "/resources/" + 
                 BPELFilename)); 
      DOMSource source = new DOMSource(doc); 
      transformer.transform(source, result); 
     } catch (Exception e) { 
      /* ParserConfigurationException */ 
      /* SAXException */ 
      /* IOException */ 
      /* TransformerConfigurationException */ 
      /* TransformerException */ 
      /* Exception */ 
      e.printStackTrace(); 
     } 
    } 
} 

Respuesta

14

Ok, Aaron Digulla me ganó la velocidad. Tuve que resolverlo yo también. no usé cnl.item(i+1) pero nextSibling():

Element newElement = doc.createElement(stepType); // Element to be inserted 
newElement.setAttribute("name", stepName); 
elem.getParentNode().insertBefore(newElement, elem.getNextSibling()); 

No puede insertar nodos en un índice especificado. Los únicos métodos de nodo a insertar son

appendChild(Node node) //appends the given child to the end of the list of children 

y

insertBefore(Node new, Node child) //inserts "new" into the list, before the 'child' node. 

Si había un método InsertAfter (Nodo nuevo, hijo del nodo), esto sería muy fácil para usted. Pero no hay, lamentablemente.

+1

¿Qué ocurre si 'elem.getNextSibling() == null'? – Stephan

+2

@Stephan de [los documentos de insertBefore] (https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Node.html#insertBefore (org.w3c.dom.Node,%) 20org.w3c.dom.Node)): '' Si [el segundo parámetro] es nulo, inserte newChild al final de la lista de niños. – f1sh

4

Es muy sencillo, pero la API org.w3c.dom es un poco ... extraño para esto:

Node next = cnl.item(i + 1); 
Node newChild = createChild(); 
next.getParent().insertBefore(newChild, next); 

Con jdom , es más simple:

Node newChild = createChild(); 
cnl.getParent().addContent(i, newChild); 
+0

Gracias por la respuesta @ Aaron, pero ¿y si quiero insertar inmediatamente después de "Reply1". No hay próximo para Reply1 (o puedo entenderlo mal). –

+0

@Andrei: en ese caso, 'cnl.item (i + 1)' devuelve 'null'. Eso puede sonar peligroso, pero el javadoc para 'insertBefore (Node newChild, Node refChild)' dice: "Si refChild es nulo, inserte newChild al final de la lista de elementos secundarios", que da como resultado exactamente lo que desea. – f1sh

+0

@ f1sh ¡Gracias, está funcionando! –

2

Esto no se ha probado, pero debe ser capaz de hacer:

elem.getParentNode().insertBefore(newElement, elem.getNextSibling()); 
2

Como otros han señalado, la API DOM es bastante detallado para tales operaciones simples. Si utiliza algo así como jOOX para envolver la API DOM, se podría escribir cualquiera de los siguientes:

// Find the element using XPath, and insert XML text after it 
$(document).xpath("//sequence/assign[@name='Assign1']") 
      .after("<newtype name=\"NewNode\"/>"); 

// Find the element using jOOX API, and insert an object after it 
$(document).find("sequence") 
      .find("assign") 
      .filter(attr("name", "Assign1")) 
      .after($("newtype").attr("name", "NewNode")); 

Nota cómo el API se parece al de jQuery.

Cuestiones relacionadas