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
Launching Spring Application Address Already in Use
How to Persist a Property of Type List<String> in Jpa
Java: Getting a Substring from a String Starting After a Particular Character
How to Upload a Document to Sharepoint With Java
How to Run Selenium Webdriver in the Background
Classcastexception Because of Classloaders
Using an Empty Keystore Password Used to Be Possible
How to Check If a Java 8 Stream Is Empty
How to Mock Resultset and Populate It Using Mockito in Java
Passing Data into HTML from Java Via Spring
Java Nullpointerexception When Adding to Arraylist
Pass and Get Json String to Spring Controller
Rsa Decryption Error - Illegalblocksizeexception: Data Must Not Be Longer Than 128 Bytes
Spring-Boot @Autowired Interface (Crudrepository) in My Service Class => Null Pointer Exception
How to Return Different Results When Calling the Same Mocked Method