tags:

views:

38

answers:

3

Given the following XML file:

<?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"&gt;
   <sequence>
      <receive name="Receive1" createInstance="yes"/>
      <assign name="Assign1"/>
      <invoke name="Invoke1"/>
      <assign name="Assign2"/>
      <reply name="Reply1"/>
   </sequence>
</process>

I want to add a new element inside the <sequence></sequence> after a certain pre-existing element. For example if I want to add the node after "Assign1", the new XML should like this:

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

I have to do this by using Java DOM, in a function. The function signature should like this:

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

Where:

  • name is the pre-existing element, after which the insertion will be made;
  • stepType is the inserted element type;
  • stepName is the name attribute of the newly inserted element.

Currently I am lacking experience with JDOM, or any other Java XML library. Can you please give a sample code, or point me to a tutorial where an insertion after a certain element is made.

This is the code I have until now:

    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();
        }
    }
}
+1  A: 

It's simple but the org.w3c.dom API is a bit ... odd for this:

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

With JDom, it's more simple:

Node newChild = createChild();
cnl.getParent().addContent(i, newChild);
Aaron Digulla
Thanks for the answer @Aaron, But what if I want to insert imediately after "Reply1" . There's no next for Reply1 (or I may understand it wrong).
Andrei Ciobanu
@Andrei: In that case, `cnl.item(i+1)` returns `null`. That might sound dangerous, but the javadoc for `insertBefore(Node newChild, Node refChild)` says: "If refChild is null, insert newChild at the end of the list of children", which results in exactly what you want.
f1sh
@f1sh Thanks, is working!
Andrei Ciobanu
+1  A: 

Ok, Aaron Digulla beat me regarding speed. Had to fiure it out myself as well. I didnt use cnl.item(i+1) but nextSibling():

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

You cannot insert Nodes at a specified index. The only node-inserting methods are

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

and

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

If there was a insertAfter(Node new, Node child) method, this would be very easy for you. But there isn't.

f1sh
+1  A: 

This is not tested but you should be able to do:

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