Solved

JDOM - finding a nested CHILD ELEMENT

Posted on 2002-06-26
26
1,075 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
  • 14
  • 11
26 Comments
 

Author Comment

by:jsm11482
Comment Utility
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
Comment Utility
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
Comment Utility
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
 

Author Comment

by:jsm11482
Comment Utility
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
Comment Utility
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
Comment Utility
'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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
OK, I'll have a look at the code
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
Comment Utility
In the meantime (to use your pseudo-document) I assume findElement("E1",E1") doesn't return null!?
0
 
LVL 86

Expert Comment

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

Author Comment

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

Expert Comment

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

Expert Comment

by:CEHJ
Comment Utility
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
Comment Utility
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
Comment Utility
So we could adapt that to work with JDOM then?
-Josh
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Thanks for all of the time and effort, I will work on implementing your ideas! Here are your points!
Thanks,
Josh
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
array220 challenge 8 44
topping1 challenge 7 47
wordappend challenge 8 83
Requested array size exceeds VM limit 3 44
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…
Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

763 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

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now