2010-08-04 12 views
8

Dato il seguente file XML:Java DOM - Inserimento di un elemento, dopo l'altro

<?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> 

voglio aggiungere un nuovo elemento all'interno della <sequence></sequence>dopo un certo elemento preesistente. Per esempio se voglio aggiungere il nodo dopo "Assign1", il nuovo XML dovrebbe in questo modo:

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

devo farlo utilizzando Java DOM, in una funzione. La firma funzione desidero questo:

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

Dove:

  • name è l'elemento preesistente, dopo di che sarà fatta l'inserimento;
  • stepType è il tipo di elemento inserito;
  • stepName è l'attributo nome dell'elemento appena inserito.

Attualmente mi manca esperienza con JDOM o qualsiasi altra libreria XML Java. Potete per favore fornire un codice di esempio o indicarmi un tutorial in cui viene inserito un inserimento dopo che un determinato elemento è stato creato.

Questo è il codice che ho finora:

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

risposta

14

Ok, Aaron Digulla mi ha battuto per quanto riguarda la velocità. Ho dovuto capire anche me stesso. Non ho usato cnl.item(i+1) ma nextSibling():

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

Non è possibile inserire nodi in un indice specificato. Gli unici metodi nodo-inserimento sono

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

e

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

Se ci fosse un metodo InsertAfter (Node nuova, nodo figlio), questo sarebbe molto facile per voi. Ma non c'è, sfortunatamente.

+1

Cosa succede se 'elem.getNextSibling() == null'? – Stephan

+2

@Stephan from [the docs of insertBefore] (https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Node.html#insertBefore (org.w3c.dom.Node,% 20org.w3c.dom.Node)): '' Se [il secondo parametro] è nullo, inserire newChild alla fine dell'elenco dei bambini .'' – f1sh

4

E 'semplice, ma l'API org.w3c.dom è un po' ... strano per questo:

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

Con JDOM , è più semplice:

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

Grazie per la risposta @Aaron, ma cosa succede se voglio inserire immediatamente dopo "Rispondi1". Non c'è il prossimo per Reply1 (o potrei capirlo male). –

+0

@Andrei: In questo caso, 'cnl.item (i + 1)' restituisce 'null'. Potrebbe sembrare pericoloso, ma il javadoc per 'insertBefore (Node newChild, Node refChild)' dice: "Se refChild è nullo, inserisci newChild alla fine dell'elenco dei bambini", il risultato è esattamente quello che vuoi. – f1sh

+0

@ f1sh Grazie, sta funzionando! –

2

Questo non è testato, ma si dovrebbe essere in grado di fare:

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

Come altri hanno fatto notare, l'API DOM è abbastanza dettagliato per tali operazioni semplici. Se si utilizza qualcosa come jOOX per avvolgere l'API DOM, si potrebbe scrivere una delle seguenti:

// 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")); 

Si noti come l'API assomiglia a quella di jQuery.

Problemi correlati