JDOM - finding a nested CHILD ELEMENT

Hi, I need help creating a loop that will find a child element ANYWHERE in the JDOM Document.  For instance, my document is as follows:
<ROOT>
  <E1>
    <E1A>TEXT AND SUCH</E1A>
    <E1B>
      <E1B1>text...</E1B1>
    </E1B>
  </E1>
</ROOT>
To find a first-level child is easy: ROOT.getChild("E1"); However, to find a nested child (E1B1 for instance) you need a loop to look through the root element for E1B1, if we dont find it there, look through all of the second level elements (E1A and E1B), and so on until either we reach the end of the structure or we find the element E1B1.  I need this loop to be generic, that is, it will work for ANY JDOM XML Document structure, with and number of levels and elements.  This is a brain teaser (at least for me) I am sick of racking my brain on the loop code - I am not a pro Java developer...yet.  Thanks to all who try to answer this question!

EMAIL ME WITH *ANY* QUESTIONS!
Thanks,
Josh
jsm11482Asked:
Who is Participating?
 
CEHJCommented:
I'll certainly help *you* do the alteration. What I would recommend is for you to start your own DOM utility library, of which DomUtils could be the start. Keep it in a separate package, such as 'xxx.domutils'. In the meantime, as a quick solution, all you need to do is drop the class DomUtils straight into XMLParser.java and it should work.

In future it's considered good style (cf the excellent guide 'The Element's of Java Style' http://www.amazon.co.uk/exec/obidos/ASIN/0521777682/proteanit-20 [and it's not *just* style] ) when a class name contains an acronym, such as XML, to only capitalise the first letter.
0
 
jsm11482Author Commented:
ONE MORE THING!
When the loop finds the element we're looking for, it should be returned as an element, not a string or integer!
Thanks,
Josh
0
 
CEHJCommented:
I haven't tried this code, so there might be the odd bug here and there!

  Element findElement(String name,Element startElement){
    if (startElement.getName().equals(name)) return startElement;
    List nodes = startElement.getChildren();
    Iterator iter = nodes.iterator();
    // Recurse if there are any child nodes
    while(iter.hasNext()){
      findElement(name,(Element)iter.next());
    }
  }
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
CEHJCommented:
Just in case you need to know the imports:
  Element findElement(String name,Element startElement){
    if (startElement.getName().equals(name)) return startElement;
    java.util.List nodes = startElement.getChildren();
    java.util.Iterator iter = nodes.iterator();
    // Recurse if there are any child nodes
    while(iter.hasNext()){
      findElement(name,(Element)iter.next());
    }
  }
0
 
jsm11482Author Commented:
Good...i believe this will work fine, how would I make it so I can pass an integer to a function, and it will count through the XML structure until it gets to that element - the nth element? Does that make sense?
-Josh
0
 
jsm11482Author Commented:
Hmmm....here is the code I used:

  //Returns the requested element
  public Element getElement(String which,Element startElem)
  {
    List nodes = startElem.getChildren();
    Iterator iter = nodes.iterator();

    if(startElem.getName().equals(which)) return startElem;
    while(iter.hasNext())
    {
      System.out.println(iter.next().toString());
      getElement(which,(Element)iter.next());
    }

    return null;
  }

As you can see I added a println in there to see how many elements it looks through, it only prints out: [Element: <ELEMENT_1/>] which means that it doesnt get past the first element!
Any insight?
Thanks,
-Josh
0
 
CEHJCommented:
'return null;'
That's right - I should have included that in my code. Just a preliminary before we go on: tell me, in terms of the document, what node you want. What is it about the node in question that makes it different?
0
 
jsm11482Author Commented:
Nothing makes it different, its just nested! And that loop only loops throught he first node for some reason.  Maybe I copied it wrong or something!
-Josh
0
 
CEHJCommented:
Just so I know exactly what we're talking about here, can you post the document, or at least some of the parts around the node you're talking about?
0
 
jsm11482Author Commented:
hmmm i will put the source code (.java) files as they appear now on my web site:

http://www30.brinkster.com/jsment/CodeSource/Java/XMLParser/XMLParser.java

http://www30.brinkster.com/jsment/CodeSource/Java/XMLParser/XMLtest.java

XMLParser is the document with getElement(String,Element) in it, that is what we are working with! XMLTest is a class that will test XMLParser and XMLString (an in-house XML Parser) and compare execution time and such.  I can not release XMLString as it is one of our software products.  Just comment out any lines that include the word XMLString or reference that somehow, also get rid of the import of com.newsbank.xml.XMLString.

Let me know if anything above does not work!
Thanks,
Josh
0
 
CEHJCommented:
OK, I was thinking more of the document itself actually. Are you saying (to use your document example) it's not finding element E1B1?
0
 
jsm11482Author Commented:
hmmm i will put the source code (.java) files as they appear now on my web site:

http://www30.brinkster.com/jsment/CodeSource/Java/XMLParser/XMLParser.java

http://www30.brinkster.com/jsment/CodeSource/Java/XMLParser/XMLtest.java

XMLParser is the document with getElement(String,Element) in it, that is what we are working with! XMLTest is a class that will test XMLParser and XMLString (an in-house XML Parser) and compare execution time and such.  I can not release XMLString as it is one of our software products.  Just comment out any lines that include the word XMLString or reference that somehow, also get rid of the import of com.newsbank.xml.XMLString.

Let me know if anything above does not work!
Thanks,
Josh
0
 
jsm11482Author Commented:
Yeah it won't find any elements, that is, in the XMLTest class when it says "Finding element...." if calls the getElement function and it always returns a null object! The document is created statically in the XMLTest class in the function textXMLParser.
Thanks,
Josh
0
 
CEHJCommented:
OK, I'll have a look at the code
0
 
CEHJCommented:
Your site won't let me in there. You can zip and mail if you want to cehjohnson@aol.com.
0
 
CEHJCommented:
In the meantime (to use your pseudo-document) I assume findElement("E1",E1") doesn't return null!?
0
 
CEHJCommented:
Sorry, assume that the second parameter there is  the variable E1 holding a reference to an E1 element.
0
 
jsm11482Author Commented:
Ill send the zip now, and yes, any item i search for returns null!
-josh
0
 
CEHJCommented:
Actually, I can see the source all of a sudden!
0
 
CEHJCommented:
What we need to do (it might help you to see the problem as well)is to get into the position where I've got compilable code, which means bypassing XMLString for the moment.
0
 
cehjohnsonCommented:
This example uses your document example (included at the end in comment):

import javax.xml.parsers.*;
import org.w3c.dom.*;

class FindNode {


     public static Node findNode(Node node, String name) {
          if (node.getNodeName().equals(name)) {
               return node;
          }
          if (node.hasChildNodes()) {
               NodeList list = node.getChildNodes();
               int size = list.getLength();
               for (int i = 0; i < size; i++) {
                    Node found = findNode(list.item(i), name);
                    if (found != null) {
                         return found;
                    }
               }
          }
          return null;
     }


     public static void main(String[] args) {
          buildDom();
     }

     public static void buildDom() {
          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
          try {
               DocumentBuilder builder = factory.newDocumentBuilder();
               Document document = builder.newDocument();
               Element root = document.createElement("ROOT");
               document.appendChild(root);
               Element E1 = document.createElement("E1");
               root.appendChild(E1);
               Element E1A = document.createElement("E1A");
               E1.appendChild(E1A);
               Element E1B = document.createElement("E1B");
               E1.appendChild(E1B);
               Element E1B1 = document.createElement("E1B1");
               E1B1.appendChild(document.createTextNode("You've found me!"));
               E1B.appendChild(E1B1);
               Node n = findNode(root,"E1B1");
               if (n != null) {
                    System.out.println((n = n.getLastChild()) != null? n.getNodeValue() : "Who stole my text?!");
               }

          } catch (Exception e) {
                e.printStackTrace();
          }
     }

}

/*
<ROOT>
 <E1>
   <E1A>TEXT AND SUCH</E1A>
   <E1B>
     <E1B1>You've found me!</E1B1>
   </E1B>
 </E1>
</ROOT>
*/
0
 
jsm11482Author Commented:
So we could adapt that to work with JDOM then?
-Josh
0
 
CEHJCommented:
Yes, it could. I did it in JDK classes as I've not got JDOM installed, but since I was thinking of getting it anyway, I may send you an adapted version later.
0
 
CEHJCommented:
Here it is as a utility class adapted for JDOM:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.jdom.input.DOMBuilder;
import org.jdom.Element;
import java.util.Iterator;
import java.util.List;

class FindNode {

     public static Node findNode(Node node, String name) {
          if (node.getNodeName().equals(name)) {
               return node;
          }
          if (node.hasChildNodes()) {
               NodeList list = node.getChildNodes();
               int size = list.getLength();
               for (int i = 0; i < size; i++) {
                    Node found = findNode(list.item(i), name);
                    if (found != null) {
                         return found;
                    }
               }
          }
          return null;
     }

     public static void main(String[] args) {
          buildDom();
     }

     public static void buildDom() {
          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
          try {
               DocumentBuilder builder = factory.newDocumentBuilder();
               Document document = builder.newDocument();
               org.w3c.dom.Element root = document.createElement("ROOT");
               document.appendChild(root);
               org.w3c.dom.Element E1 = document.createElement("E1");
               root.appendChild(E1);
               org.w3c.dom.Element E1A = document.createElement("E1A");
               E1.appendChild(E1A);
               org.w3c.dom.Element E1B = document.createElement("E1B");
               E1.appendChild(E1B);
               org.w3c.dom.Element E1B1 = document.createElement("E1B1");
               E1B1.appendChild(document.createTextNode("You've found me!"));
               E1B.appendChild(E1B1);

               // Now create a JDOM document to test the finder
               DOMBuilder jdomBuilder = new DOMBuilder();
               org.jdom.Document doc = jdomBuilder.build(document);
               org.jdom.Element e = DomUtils.getElement("E1B1", doc.getRootElement());
               String s = null;
               System.out.println(e != null && (s = e.getText()) != null ? s : "Who stole my element/text?!");
               
          } catch (Exception e) {
               e.printStackTrace();
          }
     }


}

/**
 * Various utilties for manipulating XML DOMs
 *
 * @author     Josh
 * @created    03 July 2002
 */
class DomUtils {


     /**
      * Gets a child element given a starting parent element
      *
      * @param  which      The name of the element to find
      * @param  startElem  The starting element
      * @return            The element found
      */
     public static Element getElement(String which, org.jdom.Element startElem) {
          if (startElem.getName().equals(which)) {
               return startElem;
          }
          if (startElem.hasChildren()) {
               List nodes = startElem.getChildren();
               Iterator iter = nodes.iterator();
               while (iter.hasNext()) {
                    org.jdom.Element found = getElement(which, (org.jdom.Element) iter.next());
                    if (found != null) {
                         return found;
                    }
               }
          }
          return null;
     }

}

/*
 *  <ROOT>
 *  <E1>
 *  <E1A>TEXT AND SUCH</E1A>
 *  <E1B>
 *  <E1B1>You've found me!</E1B1>
 *  </E1B>
 *  </E1>
 *  </ROOT>
 */
0
 
jsm11482Author Commented:
Great! Now, I am new to Java, would it be too much trouble for me to ask you to change that XMLParser.java file that I emailed you and put your code in there because I am not exactly sure how it works!
You already won the points, obviously, so you don't have to do this, just let me know!
Thanks,
Josh
0
 
jsm11482Author Commented:
Thanks for all of the time and effort, I will work on implementing your ideas! Here are your points!
Thanks,
Josh
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.