Solved

JDOM - finding a nested CHILD ELEMENT

Posted on 2002-06-26
26
1,130 Views
Last Modified: 2012-05-04
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
0
Comment
Question by:jsm11482
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 11
26 Comments
 

Author Comment

by:jsm11482
ID: 7113244
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7113261
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7113300
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:jsm11482
ID: 7115434
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
 

Author Comment

by:jsm11482
ID: 7116116
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7118179
'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
 

Author Comment

by:jsm11482
ID: 7121569
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7121588
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
 

Author Comment

by:jsm11482
ID: 7122239
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122270
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
 

Author Comment

by:jsm11482
ID: 7122484
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
 

Author Comment

by:jsm11482
ID: 7122492
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122494
OK, I'll have a look at the code
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122560
Your site won't let me in there. You can zip and mail if you want to cehjohnson@aol.com.
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122579
In the meantime (to use your pseudo-document) I assume findElement("E1",E1") doesn't return null!?
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122584
Sorry, assume that the second parameter there is  the variable E1 holding a reference to an E1 element.
0
 

Author Comment

by:jsm11482
ID: 7122625
Ill send the zip now, and yes, any item i search for returns null!
-josh
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122711
Actually, I can see the source all of a sudden!
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7122735
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
 

Expert Comment

by:cehjohnson
ID: 7123401
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
 

Author Comment

by:jsm11482
ID: 7124914
So we could adapt that to work with JDOM then?
-Josh
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 7126289
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 7126825
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
 

Author Comment

by:jsm11482
ID: 7127280
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
 
LVL 86

Accepted Solution

by:
CEHJ earned 200 total points
ID: 7128624
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
 

Author Comment

by:jsm11482
ID: 7137648
Thanks for all of the time and effort, I will work on implementing your ideas! Here are your points!
Thanks,
Josh
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Error in @AspectJ Based AOP with Spring 2 23
by zero exception 10 70
java imports not found 4 51
Java Eclipse Loop 3 31
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question