Reputation: 31
I have the following XML structure :
<?xml version="1.0" encoding="UTF-8"?>
<root>
<person name="foobar">
<age>45</age>
<city>SOTown</city>
</person>
<person name="tester">
<age>51</age>
<city>There</city>
</person>
</root>
I'm using SAXParser and I can get the node elements like this (it's simplified) :
ArrayList<Person> persons = new ArrayList<Person>();
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
if (name.equals("person")){
Person p = new Person();
p.name = attributes.getValue("name");
p.age = ???
p.city = ???
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
}
The problem is at the p.age
and p.city
lines.
How can I get that child nodes values ?
Thank you.
Upvotes: 3
Views: 12251
Reputation: 60414
You can change the content handler during processing, which allows you to maintain state and do contextual processing. For example, consider this self-contained example:
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class SAXHandler extends DefaultHandler {
private XMLReader reader;
private List<Person> people = new ArrayList<Person>();
public static void main(String[] args) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
SAXHandler tester = new SAXHandler(saxParser.getXMLReader());
saxParser.parse("workbook.xml", tester);
System.out.println(tester.people);
} catch (Exception e) {
e.printStackTrace();
}
}
public SAXHandler(XMLReader reader) {
this.reader = reader;
}
public Person addPerson(Person person) {
this.people.add(person);
return person;
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if ("person".equals(qName)) {
String name = attributes.getValue("name");
this.reader.setContentHandler(new PersonHandler(this.reader, this,
name));
}
System.out.println("Start Element: " + qName);
}
}
Notice that we setContentHandler
whenever we encounter a person
element. The PersonHandler
looks like this:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class PersonHandler extends DefaultHandler {
private Person currPerson;
private StringBuilder content;
private XMLReader reader;
private SAXHandler parentHandler;
public PersonHandler(XMLReader reader, SAXHandler parentHandler, String name) {
this.reader = reader;
this.parentHandler = parentHandler;
this.currPerson = new Person(name);
this.content = new StringBuilder();
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
this.content.setLength(0);
System.out.println("PersonHandler::Start Element: " + qName);
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("age".equals(qName)) {
this.currPerson.setAge(this.content.toString());
} else if ("city".equals(qName)) {
this.currPerson.setCity(this.content.toString());
} else if ("person".equals(qName)) {
this.parentHandler.addPerson(this.currPerson);
this.reader.setContentHandler(this.parentHandler);
}
System.out.println("PersonHandler::End Element: " + qName);
}
public void characters(char ch[], int start, int length)
throws SAXException {
this.content.append(ch, start, length);
}
}
Notice that we reset the content handler to the parent handler whenever we are done processing the person
.
For completeness, here's a (very) minimal Person
:
public class Person {
private String name;
private String age;
private String city;
public Person(String name) {
this.name = name;
}
public void setAge(String string) {
this.age = string;
}
public void setCity(String string) {
this.city = string;
}
public String toString() {
return this.name + " " + this.age + " " + this.city;
}
}
This code would output:
Start Element: root
Start Element: person
PersonHandler::Start Element: age
PersonHandler::End Element: age
PersonHandler::Start Element: city
PersonHandler::End Element: city
PersonHandler::End Element: person
Start Element: person
PersonHandler::Start Element: age
PersonHandler::End Element: age
PersonHandler::Start Element: city
PersonHandler::End Element: city
PersonHandler::End Element: person
Upvotes: 7
Reputation: 3996
Use this code : Replace start and End Elements and Declare Person class object in top...
ArrayList<Person> persons = new ArrayList<Person>();
String content;
Person p;
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException
{
if (localName.equals("person")) {
p = new Person();
p.name = attributes.getValue("name");
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
if (localName.equals("age")) {
p.age = = Integer.parseInt(content.toString());
}
if (localName.equals("city")) {
p.city = content;
}
if (localName.equals("person")) {
persons.add(p);
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
content= new String(ch, start, length);
}
Any doubt or suggestion ?, You are welcomed...
Upvotes: 0
Reputation: 34014
You can't directly, you would have to set a boolean instance variable to
indicate you are now inside a person
element and set the persons attributes
inside the endElement
method. The character content gets passed to the
characters
method and has to be appended to a buffer since the parser is
allowed to call this method multiple times.
StringBuilder content = new StringBuilder();
boolean inPerson = false;
Person person;
// characters can be called multiple times per element, so aggregate the content in a StringBuilder
public void characters(char[] ch, int start, int length) throws SAXException {
content.append(ch, start, length);
}
public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {
// reset the character buffer
content.setLength(0);
if (localName.equals("person")) {
this.person = new Person();
this.person.name = attributes.getValue("name");
this.inPerson = true;
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (inPerson) {
if (localName.equals("age")) {
this.person.age = Integer.parseInt(content.toString());
} else if (localName.equals("city")) {
this.person.city = content.toString();
} else if (localName.equals("person")) {
this.inPerson = false;
}
}
}
Upvotes: 4