So I am facing this issue where I am required to parse an XML file to popluate domain objects. Sounds simple enough, however, an element within the XML file can have an unknown ammount of children, hence the domain object can have a instance variable to another object of the class, that object can have a variable to an instance variable of the same class and so on. To give you an example, this is a provided example for the XML file:
<categories>
<category id="1">
<name>XML</name>
<category id="2">
<name>XPath</name>
</category>
<category id="3">
<name>XML Schema</name>
</category>
<category id="4">
<name>XSLT</name>
</category>
<category id="5">
<name>XSL-FO</name>
</category>
<category id="6">
<name>XQuery</name>
</category>
</category>
<category id="7">
<name>Java</name>
<category id="100">
<name>SDK</name>
<category id="8">
<name>Collections</name>
</category>
<category id="9">
<name>NIO</name>
</category>
<category id="10">
<name>Concurrency</name>
</category>
</category>
<category id="1000">
<name>EE</name>
<category id="11">
<name>EJB</name>
</category>
<category id="12">
<name>Web</name>
</category>
<category id="13">
<name>Webservices</name>
</category>
</category>
<category id="0">
<name>Examen boeken</name>
</category>
</category>
</categories>
I have already done this with a DOM parser but for my study I am required to do this with a SAX parser aswell. I am getting stuck on the point where I need to tell which element has which elements as children and which element has which element as parent.
As of now I managed to get all category entries in a map containing their ID and name.
The code looks like this:
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException {
Bookshelf mijnBookshelf = new Bookshelf("boekenfestijn");
Map<Integer, Category> categories = new HashMap<Integer, Category>();
// TODO inlezen
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
String reading = null;
boolean inCategory = false;
boolean inName = false;
int categoryId;
Category currentCategory;
public void startElement(String uri, String localName,
String qName, Attributes attributes)
throws SAXException {
if(qName.equalsIgnoreCase("CATEGORY") && attributes.getValue("id") != null){
inCategory = true;
categoryId = Integer.parseInt(attributes.getValue("id"));
System.out.println("START HANDLING ID -> " + attributes.getValue("id"));
}
if(qName.equalsIgnoreCase("NAME")){
inName = true;
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
if(inCategory){
inCategory = false;
System.out.println("CATEGORY ID : " + categoryId + " NAME : " + reading);
currentCategory = new Category(categoryId, reading);
currentCategory.setBookshelf(mijnBookshelf);
categories.put(categoryId, currentCategory);
System.out.println("END HANDLING");
}
if(inName){
inName = false;
}
}
public void characters(char ch[], int start, int length)
throws SAXException {
reading = new String(ch, start, length);
}
};
saxParser.parse("bookshelf.xml", handler);
} catch (Exception e) {
e.printStackTrace();
}
for (Integer i : categories.keySet()) {
System.out.println("ID: " + categories.get(i).getId() + "->"
+ categories.get(i).getName());
}
And for the "category" class
public class Category {
private Integer id;
private String name;
private Category parent;
private List<Category> children = new ArrayList<Category>();
private Bookshelf bookshelf;
public Category(){
}
public Category(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getParent() {
return parent;
}
public void setParent(Category parent){
this.parent = parent;
}
public List<Category> getChildren() {
return children;
}
public String toString() {
String s = bookshelf.getName() + "/";
if (parent != null) {
s = parent.toString();
}
s += name + "/";
return s;
}
public Bookshelf getBookshelf() {
return bookshelf;
}
public void setBookshelf(Bookshelf bookshelf) {
this.bookshelf = bookshelf;
}
And this is the point at which I am getting stuck? how could I proceed to define the parent child relations? how would I know in any point in my handler which element has which element as children / parent?
Any help would be greatly appreciated!
TLDR: How can one define parent / child relations when using a sax parser to populate domain objects ?
In SAX, you can not know directly which element is the parent of another. A common way to handle this information is managing a LIFO stack (e.g. java.util.Stack
). You push the element on the startElement()
method and pop it on the endElement()
.
And unfortunately it is not possible to forecast the child elements until you "met" them thanks to a startElement()
.