Parse Xml to Java Pojo in Efficient Way

Parsing XML into Java object

The simplest way to work with a XML is to serialize it to an object.

You can do it with JAXB, here is an tutorial: mykong

Just define how objects should look like.

Here is an example:

@XmlRootElement(name = "entry_list")
public class EntryList {

@XmlElement(name = "entry")
private List<Entry> entities;

public List<Entry> getEntities() {
return entities;
}
public void setLastName(List<Entry> entities) {
this.entities = entities;
}
}

public class Entry {

@XmlAttribute
private String id;

@XmlElement
private Sound sound

etc
...

public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}

public Sound getSound() {
return sound;
}
public void setSound(Sound sound) {
this.sound = sound;
}
}

Every element that got a child element have to be a class and if it repeats multiple times like entry or vi it should be a list.

XML to POJO JAVA

Managed to figure it out.

@XmlRootElement(name = "REQUERYTRXRESPONSE")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response {

private String param1;
private String param2;
private String param3;

public String getParam1() {
return param1;
}

public void setParam1(String param1) {
this.param1 = param1;
}

public String getParam2() {
return param2;
}

public void setParam2(String param2) {
this.param2 = param2;
}

public String getParam3() {
return param3;
}

public void setParam3(String param3) {
this.param3 = param3;
}

}

You don't need to specify the @XmlElement when you do the @XxmlAccessorType unless you wanted the required=true part.

What I changed is that I moved the namespace from @XmlRootElement in a package-info.java class like so:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://tempuri.org/",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.sfatandrei.soplayground.model;

My main test method includes:

  final InputStream resourceAsStream = SoPlaygroundApplication.class.getClassLoader().getResourceAsStream("test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Response.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Response response = (Response) unmarshaller.unmarshal(resourceAsStream);
System.out.println(response);

Better way to parse xml

Here's an example of using JAXB with StAX.

Input document:

<?xml version="1.0" encoding="UTF-8"?>
<Personlist xmlns="http://example.org">
<Person>
<Name>Name 1</Name>
<Address>
<StreetAddress>Somestreet</StreetAddress>
<PostalCode>00001</PostalCode>
<CountryName>Finland</CountryName>
</Address>
</Person>
<Person>
<Name>Name 2</Name>
<Address>
<StreetAddress>Someotherstreet</StreetAddress>
<PostalCode>43400</PostalCode>
<CountryName>Sweden</CountryName>
</Address>
</Person>
</Personlist>

Person.java:

@XmlRootElement(name = "Person", namespace = "http://example.org")
public class Person {
@XmlElement(name = "Name", namespace = "http://example.org")
private String name;
@XmlElement(name = "Address", namespace = "http://example.org")
private Address address;

public String getName() {
return name;
}

public Address getAddress() {
return address;
}
}

Address.java:

public class Address {
@XmlElement(name = "StreetAddress", namespace = "http://example.org")
private String streetAddress;
@XmlElement(name = "PostalCode", namespace = "http://example.org")
private String postalCode;
@XmlElement(name = "CountryName", namespace = "http://example.org")
private String countryName;

public String getStreetAddress() {
return streetAddress;
}

public String getPostalCode() {
return postalCode;
}

public String getCountryName() {
return countryName;
}
}

PersonlistProcessor.java:

public class PersonlistProcessor {
public static void main(String[] args) throws Exception {
new PersonlistProcessor().processPersonlist(PersonlistProcessor.class
.getResourceAsStream("personlist.xml"));
}

// TODO: Instead of throws Exception, all exceptions should be wrapped
// inside runtime exception
public void processPersonlist(InputStream inputStream) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
XMLStreamReader xss = XMLInputFactory.newFactory().createXMLStreamReader(inputStream);
// Create unmarshaller
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// Go to next tag
xss.nextTag();
// Require Personlist
xss.require(XMLStreamReader.START_ELEMENT, "http://example.org", "Personlist");
// Go to next tag
while (xss.nextTag() == XMLStreamReader.START_ELEMENT) {
// Require Person
xss.require(XMLStreamReader.START_ELEMENT, "http://example.org", "Person");
// Unmarshall person
Person person = (Person)unmarshaller.unmarshal(xss);
// Process person
processPerson(person);
}
// Require Personlist
xss.require(XMLStreamReader.END_ELEMENT, "http://example.org", "Personlist");
}

private void processPerson(Person person) {
System.out.println(person.getName());
System.out.println(person.getAddress().getCountryName());
}
}

Uknown XML file into pojo

In the hope that this helps you to understand your situation!

public static void dumpAllNodes( String path ) throws Exception {
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = parser.parse(new File(path));
NodeList nodes = doc.getElementsByTagNameNS( "*", "*" );
for( int i = 0; i < nodes.getLength(); i++ ){
Node node = nodes.item( i );
System.out.println( node.getNodeType() + " " + node.getNodeName() );
}
}

The NodeList nodes contains all element nodes, in document order (opening tag). Thus, elements contained within elements will be in that list, all alike. To obtain the attributes of a node, call

NamedNodeMap map = node.getAttributes();

The text content of a node is available by

String text = node.getTextContent();

but be aware that calling this returns the text in all elements of a subtree.

OTOH, you may call

Element root = doc.getDocumentElement();

to obtain the root element and then descend the tree recursively by calling Element.getChildNodes() and process the nodes (Element, Attr, Text,...) one by one. Also, note that Node.getParentNode() returns the parent node, so you could construct the XPath for each node even from the flat list by repeating this call to the root.

It simply depends what you expect from the resulting data structure (what you call ArrayList). If, for instance, you create a generic element type (MyElement) containing one map for attributes and another one for child elements, the second map would have to be

Map<String,List<MyElement>> name2elements

to provide for repeated elements - which makes access to elements occurring only once a little awkward.

I hope that I have illustrated the problems of generic XML parsing, which is not a task where JAXB can help you.



Related Topics



Leave a reply



Submit