I'm new to xml parsing. I worked with DOM to parse the xml for practice. Now I thought to move some to other xml parsing framework. So I have chosen JAXB parser.For my requirement, I could not create getter setter for all xml tags. Because the xml which I will get is dynamic. So I do not know the tags before hand to create getter/setter.I've referred this link http://www.mkyong.com/java/jaxb-hello-world-example/. Is there any way to do parsing without creating getter and setter.Please make me clear.
4 Answers
You could leverage the @XmlAnyElement and XmlAnyAttribute annotations to map the extra content. If you don't want get/set methods just add @XmlAccessorType(XmlAccessType.FIELD) on your class.
Customer
In the class below we map a specific XML attribute and element, and then use the @XmlAnyElement annotation to map any other elements that may appear, and @XmlAnyAttribute to map any other attributes that may appear.
import java.util.*;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@XmlAttribute
int id;
@XmlAnyAttribute
Map<QName, String> otherAttributes;
String name;
@XmlAnyElement(lax=true)
List<Object> otherElements;
}
input.xml
We will unmarshal the following XML document in the demo code.
<?xml version="1.0" encoding="UTF-8"?>
<customer id="123" status="good">
<name>Jane Doe</name>
<address>
<street>1 A Street</street>
<city>Any Town</city>
</address>
<phone-number>555-1111</phone-number>
</customer>
Demo
The following document will unmarshal the XML input, dump all the resulting objects contents to System.out and the marshal the object back to XML.
import java.io.File;
import java.util.Map.Entry;
import javax.xml.bind.*;
import javax.xml.namespace.QName;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14272453/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
// Mapped XML Attribute
System.out.println("customer.id");
System.out.println(" " + customer.id);
// Other XML Attributes
System.out.println("customer.otherAttributes");
for(Entry<QName, String> entry : customer.otherAttributes.entrySet()) {
System.out.println(" " + entry);
}
// Mapped XML Element
System.out.println("customer.name");
System.out.println(" " + customer.name);
// Other XML Elements
System.out.println(customer.otherElements);
for(Object object : customer.otherElements) {
System.out.println(" " + object);
}
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
Output
Below is the output from running the demo code, note how all the fields are populated with data from the XML document.
customer.id
123
customer.otherAttributes
status=good
customer.name
Jane Doe
customer.otherElements
forum14272453.Address@24f454e4
[phone-number: null]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer id="123" status="good">
<name>Jane Doe</name>
<address>
<street>1 A Street</street>
<city>Any Town</city>
</address>
<phone-number>555-1111</phone-number>
</customer>
For More Information
Comments
For JAXB you should create variables and corresponding getters and setters for all XML tags that you might get dynamically. In case you have a tag (that you get dynamically) but you don't have a corresponding mapped variable in the Java class then you will get JAXB Exception.
Hence, you can have a tag defined in JAXB Java Class but comming in request, but the reverse a tag not defined in JAXB Class but comming in XML will give you an exception.
5 Comments
ValidationEventHandler on the Unmarshaller to make this happen if you wish. You can also enable this behaviour by specifying an instance of Schema on the Unmarshaller to enable validation. If you want the unmapped content you can leverage @XmlAnyAttribute and @XmlAnyElement: stackoverflow.com/a/14276830/383861@XmlAnyElement(lax=true) would be included with that version.This is going to be dynamic. unmarshal calls Customer.setElements; marshal calls Customer.getElements
@XmlRootElement
class Customer {
@XmlAnyElement
public void setElements(List<Element> list) {
for (Element e : list) {
String name = e.getNodeName();
String value = e.getTextContent();
}
}
public List<Element> getElements() throws ParserConfigurationException {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
List<Element> list = new ArrayList<>();
Element e = doc.createElement("e1");
e.setTextContent("v1");
list.add(e);
return list;
}
}
1 Comment
Jackson, renowned for its JSON processor, also has XML parsing support, and it does a great job of reflection so that it does the parsing even when there are no getters and setters. Give it a try.