jsm11482
asked on
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
<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
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().eq uals(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( ));
}
}
Element findElement(String name,Element startElement){
if (startElement.getName().eq
List nodes = startElement.getChildren()
Iterator iter = nodes.iterator();
// Recurse if there are any child nodes
while(iter.hasNext()){
findElement(name,(Element)
}
}
Just in case you need to know the imports:
Element findElement(String name,Element startElement){
if (startElement.getName().eq uals(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( ));
}
}
Element findElement(String name,Element startElement){
if (startElement.getName().eq
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)
}
}
ASKER
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
-Josh
ASKER
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().equ als(which) ) return startElem;
while(iter.hasNext())
{
System.out.println(iter.ne xt().toStr ing());
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
//Returns the requested element
public Element getElement(String which,Element startElem)
{
List nodes = startElem.getChildren();
Iterator iter = nodes.iterator();
if(startElem.getName().equ
while(iter.hasNext())
{
System.out.println(iter.ne
getElement(which,(Element)
}
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
'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?
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?
ASKER
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
-Josh
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?
ASKER
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
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)
Let me know if anything above does not work!
Thanks,
Josh
OK, I was thinking more of the document itself actually. Are you saying (to use your document example) it's not finding element E1B1?
ASKER
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
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)
Let me know if anything above does not work!
Thanks,
Josh
ASKER
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
Thanks,
Josh
OK, I'll have a look at the code
Your site won't let me in there. You can zip and mail if you want to cehjohnson@aol.com.
In the meantime (to use your pseudo-document) I assume findElement("E1",E1") doesn't return null!?
Sorry, assume that the second parameter there is the variable E1 holding a reference to an E1 element.
ASKER
Ill send the zip now, and yes, any item i search for returns null!
-josh
-josh
Actually, I can see the source all of a sudden!
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.
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.new Instance() ;
try {
DocumentBuilder builder = factory.newDocumentBuilder ();
Document document = builder.newDocument();
Element root = document.createElement("RO OT");
document.appendChild(root) ;
Element E1 = document.createElement("E1 ");
root.appendChild(E1);
Element E1A = document.createElement("E1 A");
E1.appendChild(E1A);
Element E1B = document.createElement("E1 B");
E1.appendChild(E1B);
Element E1B1 = document.createElement("E1 B1");
E1B1.appendChild(document. createText Node("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>
*/
import javax.xml.parsers.*;
import org.w3c.dom.*;
class FindNode {
public static Node findNode(Node node, String name) {
if (node.getNodeName().equals
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.new
try {
DocumentBuilder builder = factory.newDocumentBuilder
Document document = builder.newDocument();
Element root = document.createElement("RO
document.appendChild(root)
Element E1 = document.createElement("E1
root.appendChild(E1);
Element E1A = document.createElement("E1
E1.appendChild(E1A);
Element E1B = document.createElement("E1
E1.appendChild(E1B);
Element E1B1 = document.createElement("E1
E1B1.appendChild(document.
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>
*/
ASKER
So we could adapt that to work with JDOM then?
-Josh
-Josh
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.
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.new Instance() ;
try {
DocumentBuilder builder = factory.newDocumentBuilder ();
Document document = builder.newDocument();
org.w3c.dom.Element root = document.createElement("RO OT");
document.appendChild(root) ;
org.w3c.dom.Element E1 = document.createElement("E1 ");
root.appendChild(E1);
org.w3c.dom.Element E1A = document.createElement("E1 A");
E1.appendChild(E1A);
org.w3c.dom.Element E1B = document.createElement("E1 B");
E1.appendChild(E1B);
org.w3c.dom.Element E1B1 = document.createElement("E1 B1");
E1B1.appendChild(document. createText Node("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().equal s(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>
*/
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
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.new
try {
DocumentBuilder builder = factory.newDocumentBuilder
Document document = builder.newDocument();
org.w3c.dom.Element root = document.createElement("RO
document.appendChild(root)
org.w3c.dom.Element E1 = document.createElement("E1
root.appendChild(E1);
org.w3c.dom.Element E1A = document.createElement("E1
E1.appendChild(E1A);
org.w3c.dom.Element E1B = document.createElement("E1
E1.appendChild(E1B);
org.w3c.dom.Element E1B1 = document.createElement("E1
E1B1.appendChild(document.
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"
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().equal
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>
*/
ASKER
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
You already won the points, obviously, so you don't have to do this, just let me know!
Thanks,
Josh
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for all of the time and effort, I will work on implementing your ideas! Here are your points!
Thanks,
Josh
Thanks,
Josh
ASKER
When the loop finds the element we're looking for, it should be returned as an element, not a string or integer!
Thanks,
Josh