Nesting XML Elements in Java

D

dmckeon

I am new to Java and XML, so forgive any ignorance. I am working on a
program to create an XML document and I am having some problems with
nesting. I want something like the following:
<?xml version="1.0" encoding="UTF-8" ?>
<Employees>
<EMPLOYEE>
<NAME>
<FIRST>John</FIRST>
<LAST>Doe</LAST>
</NAME>
<TITLE>Mr.</TITLE>
<WAGE>
<RATE>Salaried</RATE>
<WAGE>40,000</WAGE>
</WAGE>
</EMPLOYEE>
</Employees>

But instead, I am getting:
<?xml version="1.0" encoding="UTF-8" ?>
<Employees>
<NAME>
<FIRST>Jeff</FIRST>
<LAST>Fry</LAST>
</NAME>
<TITLE>Senior</TITLE>
<WAGE>
<RATE>Salaried</RATE>
<WAGE>40,000</WAGE>
</WAGE>
<EMPLOYEE />
</Emplyees>

The difference being the EMPLOYEE tag. It appears to be a problem
calling the startParent method twice in a row. Here is my XML code:

package igxml;

import java.io.*;
import org.w3c.dom.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.*;
import org.apache.xml.serialize.*;

public class IgXMLBuild extends DefaultHandler {

Document doc;
Element root;
Element parentElement;
Element childElement;
Text textData;

public void startDocument(String docName)
{

// Create the DOM object
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
System.out.println("Could not locate a JAXP DocumentBuilder
class");
}
doc = builder.newDocument();

/* create the root node */
root = doc.createElement(docName);
return;
}

public Element startParent (String parentName)
{
/* create a row node */
parentElement = doc.createElement(parentName);
return parentElement;
}

public void endParent (Element parentElement)
{
/* append the row node to the root node */
root.appendChild(parentElement);
}

public void addParent(String passParentName, String
passParentValue)
{
parentElement = startParent(passParentName);
parentElement.appendChild(doc.createTextNode(passParentValue));
endParent(parentElement);
}

public void addChild(String passElementName, String passElementValue)
{
childElement = doc.createElement(passElementName);
textData = doc.createTextNode(passElementValue);
childElement.appendChild(textData);
parentElement.appendChild(childElement);
}

public String finishDocument()
{
/* append the root node to the empty document */
doc.appendChild(root);

try {
// Serialize the document
StringWriter out;
out = new StringWriter();
XMLSerializer serializer = new XMLSerializer(out, new
OutputFormat(doc));
serializer.serialize(doc);
String xmlString = out.toString();
return xmlString;
} catch (IOException e) {
System.err.println(e);
return e.toString();
}
}
}

And here is the test application I am using to call these methods:

package igxml;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.w3c.dom.*;

public class TestApp {

static DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS
");

public static void logit(String m){
System.out.println( df.format(new Date()) + m);
}

public static void main(String[] args) {
/* logit("TestApp started...");
String tranReqDoc, docList;
ImgDocList dl = new ImgDocList();
tranReqDoc = "<?xml version='1.0'
encoding='UTF-8'?><DATA><IMG-APP-ID>PS</IMG-APP-ID><IMG-FOLDER-ID>1111111111</IMG-FOLDER-ID><IMG-USER-ID>ISJAF</IMG-USER-ID></DATA>";
docList = dl.getDocList(tranReqDoc);
System.out.println(docList);
logit("TestApp finished...");*/
Element empElement;
Element nameElement;
Element wageElement;

IgXMLBuild xmlDoc = new IgXMLBuild();
xmlDoc.startDocument("Employees");
empElement = xmlDoc.startParent("EMPLOYEE");
nameElement = xmlDoc.startParent("NAME");
xmlDoc.addChild("FIRST", "John");
xmlDoc.addChild("LAST", "Doe");
xmlDoc.endParent(nameElement);
xmlDoc.addParent("TITLE", "Mr.");
wageElement = xmlDoc.startParent("WAGE");
xmlDoc.addChild("RATE", "Salaried");
xmlDoc.addChild("AMMOUNT", "40,000");
xmlDoc.endParent(wageElement);
xmlDoc.endParent(empElement);
empElement = xmlDoc.startParent("EMPLOYEE");
nameElement = xmlDoc.startParent("NAME");
xmlDoc.addChild("FIRST", "Jane");
xmlDoc.addChild("LAST", "Doe");
xmlDoc.endParent(nameElement);
xmlDoc.addParent("TITLE", "Mrs.");
wageElement = xmlDoc.startParent("WAGE");
xmlDoc.addChild("RATE", "Hourly");
xmlDoc.addChild("AMMOUNT", "42.00");
xmlDoc.endParent(wageElement);
xmlDoc.endParent(empElement);
empElement = xmlDoc.startParent("EMPLOYEE");
nameElement = xmlDoc.startParent("NAME");
xmlDoc.addChild("FIRST", "John");
xmlDoc.addChild("LAST", "Smith");
xmlDoc.endParent(nameElement);
xmlDoc.addParent("TITLE", "Sir");
wageElement = xmlDoc.startParent("WAGE");
xmlDoc.addChild("RATE", "Salaried");
xmlDoc.addChild("AMMOUNT", "48,000");
xmlDoc.endParent(wageElement);
xmlDoc.endParent(empElement);
String xmlString = xmlDoc.finishDocument();
System.out.println(xmlString);
}
}


Any idea why I can't nest that extra level???
 
O

Oliver Wong

I am new to Java and XML, so forgive any ignorance. I am working on a
program to create an XML document and I am having some problems with
nesting. I want something like the following:
<?xml version="1.0" encoding="UTF-8" ?>
<Employees>
<EMPLOYEE>
<NAME>
<FIRST>John</FIRST>
<LAST>Doe</LAST>
</NAME>
<TITLE>Mr.</TITLE>
<WAGE>
<RATE>Salaried</RATE>
<WAGE>40,000</WAGE>
</WAGE>
</EMPLOYEE>
</Employees>

But instead, I am getting:
<?xml version="1.0" encoding="UTF-8" ?>
<Employees>
<NAME>
<FIRST>Jeff</FIRST>
<LAST>Fry</LAST>
</NAME>
<TITLE>Senior</TITLE>
<WAGE>
<RATE>Salaried</RATE>
<WAGE>40,000</WAGE>
</WAGE>
<EMPLOYEE />
</Emplyees>

The difference being the EMPLOYEE tag. It appears to be a problem
calling the startParent method twice in a row. Here is my XML code:
[most of the code snipped]
public void endParent (Element parentElement)
{
/* append the row node to the root node */
root.appendChild(parentElement);
}

The reason NAME and WAGE are added to the root is because that's what your
code says to do.

- Oliver
 
D

dmckeon

But my question is why am I getting <EMPLOYEE /> rather than:
<EMPLOYEE>
....
</EMPLOYEE>
 
T

Thomas Weidenfeller

But my question is why am I getting <EMPLOYEE /> rather than:
<EMPLOYEE>
...
</EMPLOYEE>

Because that's what you have coded. You are mixing up your own
addParent/endParent methods.

As a general remark, the API of your XML builder is rather confusing and
the architecture is suboptimal. You have partly externalized state
handling (the return data from startXXX). This state (the location where
you are in the tree) should better be internal builder state. You
probably need a stack inside the builder to hold the state.

/Thomas
 
D

dmckeon

Thanks for the reply. As I said, I am VERY new to this. I was
wondering... If we had an XML schema, could we just pass in the element
name and value and then use the schema somehow to know where to nest
the value? I've seen schemas used for validation. I just wasn't sure
if they could also be used to create the XML. It sounds reasonable to
me.
 
O

Oliver Wong

Thanks for the reply. As I said, I am VERY new to this. I was
wondering... If we had an XML schema, could we just pass in the element
name and value and then use the schema somehow to know where to nest
the value? I've seen schemas used for validation. I just wasn't sure
if they could also be used to create the XML. It sounds reasonable to
me.

No, because the same element name might appear in multiple locations in
the schema.

- Oliver
 
O

Oliver Wong

Oliver Wong said:
No, because the same element name might appear in multiple locations in
the schema.

BTW, do you have to use Schemas? It might be conceptually simpler if you
just define your own tree-like abstract data type, and implement a
"toXMLString()" method on the nodes. I suggest this, because I notice that
the code you posted earlier doesn't seem to use schemas at all.

- Oliver
 
D

dmckeon

I guess I just don't know what best practice/industry standard is for
this sort of thing. No one else in my company codes Java or XML, so my
team is blazing the trail. Since I have no one to ask, I just want to
make sure I do a good job. FYI -- We're converting our COBOL system to
a web-based Java SOA system.

I understand your point about an element name appearing in multiple
places in a schema, but shouldn't there be a way to qualify it so it
knows which one you're referring to. At the very least, is there a way
to do it if all element names are unique?

We started down the path of just creating our own XML string without
using SAX or DOM or anything else. We were getting away from that in
an attempt to fit the norms of best practice. Perhaps we're going
about it incorrectly. I would love to hear from anyonw out there what
they recommend for creating XML and sample Java code would be amazing!
I'm not trying to plagarize, it's just hard to understand all of the
new terminology, so to see it in action helps me understand better.

Once again, thanks so much for your input!
 
O

Oliver Wong

I guess I just don't know what best practice/industry standard is for
this sort of thing. No one else in my company codes Java or XML, so my
team is blazing the trail. Since I have no one to ask, I just want to
make sure I do a good job. FYI -- We're converting our COBOL system to
a web-based Java SOA system.

I understand your point about an element name appearing in multiple
places in a schema, but shouldn't there be a way to qualify it so it
knows which one you're referring to. At the very least, is there a way
to do it if all element names are unique?

We started down the path of just creating our own XML string without
using SAX or DOM or anything else. We were getting away from that in
an attempt to fit the norms of best practice. Perhaps we're going
about it incorrectly. I would love to hear from anyonw out there what
they recommend for creating XML and sample Java code would be amazing!
I'm not trying to plagarize, it's just hard to understand all of the
new terminology, so to see it in action helps me understand better.

You might find this book helpful:
http://www.cafeconleche.org/books/xmljava/

- Oliver
 
Joined
May 1, 2006
Messages
1
Reaction score
0
I have something that might help you

Here goes the gratuitous self promotion. :)

I wrote a library a while back that might ease your pain as far as building XML documents goes. It's called ElementNode, and you can find it here: http://talideon.com/projects/elementnode/

Using it, the document you're looking to build would be built something like this:

ElementNode root = new ElementNode("Employees");
ElementNode employee = root.addChild("EMPLOYEE");
employee.addChild("NAME").addTextChild("FIRST", "John").addTextChild("LAST", "Doe");
employee.addChild("TITLE", "Mr.");
employee.addChild("WAGE").addTextChild("RATE", "Salaried").addTextChild("WAGE", "40,000");

String serialisedXml = root.toString();


The library automatically takes care of tag balancing.
 
Last edited:

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top