Simplest method to Convert Json to Xml - java

I have web-service in .net. When I retrieve data from database, it returns JSON File in Android Mobile. How can I convert JSON File to XML Or text.

For a simple solution, I recommend Jackson, as it can transform arbitrarily complex JSON into XML with just a few simple lines of code.
import org.codehaus.jackson.map.ObjectMapper;
import com.fasterxml.jackson.xml.XmlMapper;
public class Foo
{
public String name;
public Bar bar;
public static void main(String[] args) throws Exception
{
// JSON input: {"name":"FOO","bar":{"id":42}}
String jsonInput = "{\"name\":\"FOO\",\"bar\":{\"id\":42}}";
ObjectMapper jsonMapper = new ObjectMapper();
Foo foo = jsonMapper.readValue(jsonInput, Foo.class);
XmlMapper xmlMapper = new XmlMapper();
System.out.println(xmlMapper.writeValueAsString(foo));
// <Foo xmlns=""><name>FOO</name><bar><id>42</id></bar></Foo>
}
}
class Bar
{
public int id;
}
This demo uses Jackson 1.7.7 (the newer 1.7.8 should also work), Jackson XML Databind 0.5.3 (not yet compatible with Jackson 1.8), and Stax2 3.1.1.

Here is an example of how you can do this, generating valid XML. I also use the Jackson library in a Maven project.
Maven setup:
<!-- https://mvnrepository.com/artifact/com.fasterxml/jackson-xml-databind -->
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>jackson-xml-databind</artifactId>
<version>0.6.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.6</version>
</dependency>
Here is some Java code that first converts a JSON string to an object and then converts the object with the XMLMapper to XML and also removes any wrong element names. The reason for replacing wrong characters in XML element names is the fact that you can use in JSON element names like $oid with characters not allowed in XML. The Jackson library does not account for that, so I ended up adding some code which removes illegal characters from element names and also the namespace declarations.
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.xml.XmlMapper;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Converts JSON to XML and makes sure the resulting XML
* does not have invalid element names.
*/
public class JsonToXMLConverter {
private static final Pattern XML_TAG =
Pattern.compile("(?m)(?s)(?i)(?<first><(/)?)(?<nonXml>.+?)(?<last>(/)?>)");
private static final Pattern REMOVE_ILLEGAL_CHARS =
Pattern.compile("(i?)([^\\s=\"'a-zA-Z0-9._-])|(xmlns=\"[^\"]*\")");
private ObjectMapper mapper = new ObjectMapper();
private XmlMapper xmlMapper = new XmlMapper();
String convertToXml(Object obj) throws IOException {
final String s = xmlMapper.writeValueAsString(obj);
return removeIllegalXmlChars(s);
}
private String removeIllegalXmlChars(String s) {
final Matcher matcher = XML_TAG.matcher(s);
StringBuffer sb = new StringBuffer();
while(matcher.find()) {
String elementName = REMOVE_ILLEGAL_CHARS.matcher(matcher.group("nonXml"))
.replaceAll("").trim();
matcher.appendReplacement(sb, "${first}" + elementName + "${last}");
}
matcher.appendTail(sb);
return sb.toString();
}
Map<String, Object> convertJson(String json) throws IOException {
return mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
}
public String convertJsonToXml(String json) throws IOException {
return convertToXml(convertJson(json));
}
}
Here is a JUnit test for convertJsonToXml:
#Test
void convertJsonToXml() throws IOException, ParserConfigurationException, SAXException {
try(InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("json/customer_sample.json")) {
String json = new Scanner(in).useDelimiter("\\Z").next();
String xml = converter.convertJsonToXml(json);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
Node first = doc.getFirstChild();
assertNotNull(first);
assertTrue(first.getChildNodes().getLength() > 0);
}
}

No direct conversion API is available in android to convert JSON to XML. You need to parse JSON first then you will have to write logic for converting it to xml.

Standard org.json.XML class converts between JSON and XML in both directions. There is also tutorial on how to use it.
The conversion is not very nice as it does not create XML attributes at all (entities only), so XML output is more bulky than could possibly be. But it does not require to define Java classes matching the data structures that need to be converted.

Underscore-java library has static method U.jsonToXml(string). Live example
import com.github.underscore.U;
public class MyClass {
public static void main(String args[]) {
String json = "{\"Price\": {"
+ " \"LineItems\": {"
+ " \"LineItem\": {"
+ " \"UnitOfMeasure\": \"EACH\", \"Quantity\": 2, \"ItemID\": \"ItemID\""
+ " }"
+ " },"
+ " \"Currency\": \"USD\","
+ " \"EnterpriseCode\": \"EnterpriseCode\""
+ "}}";
System.out.println(U.jsonToXml(json));
}
}
Output:
<?xml version="1.0" encoding="UTF-8"?>
<Price>
<LineItems>
<LineItem>
<UnitOfMeasure>EACH</UnitOfMeasure>
<Quantity number="true">2</Quantity>
<ItemID>ItemID</ItemID>
</LineItem>
</LineItems>
<Currency>USD</Currency>
<EnterpriseCode>EnterpriseCode</EnterpriseCode>
</Price>

Related

How to keep xml attribute in fasterXml Jackson XmlMapper?

I am writing test cases which test generated xml structures. I am supplying the xml structures via an xml file. I am using currently FasterXMLs Jackson XmlMapper for reading and testing for expected xml.
Java: adoptopenjdk 11
Maven: 3.6.3
JUnit (Jupiter): 5.7.1 (JUnit Jupiter)
Mapper: com.fasterxml.jackson.dataformat.xml.XmlMapper
Dependency: <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.4</version>
</dependency>
I have an xml file which contains expected xml (e.g.: /test/testcases.xml:
<testcases>
<testcase1>
<response>
<sizegroup-list>
<sizeGroup id="1">
<sizes>
<size>
<technicalSize>38</technicalSize>
<textSize>38</textSize>
<size>
<size>
<technicalSize>705</technicalSize>
<textSize>110cm</textSize>
<size>
</sizes>
</sizeGroup-list>
</response>
</testcase1>
</testcases>
My code looks like this (simplified):
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
class Testcases {
private static final String OBJECT_NODE_START_TAG = "<ObjectNode>";
private static final String OBJECT_NODE_CLOSE_TAG = "</ObjectNode>";
private static final String TESTCASES_XML = "/test/testcases.xml";
private static final XmlMapper XML_MAPPER = new XmlMapper();
#Test
void testcase1() throws Exception {
final String nodePtr = "/testcase1/response";
try (InputStream inputStream = new FileInputStream(TESTCASES_XML)) {
JsonNode rootNode = XML_MAPPER.readTree(inputStream);
JsonNode subNode = rootNode.at(nodePtr);
if (subNode.isMissingNode()) {
throw new IllegalArgumentException(
"Node '" + nodePtr + "' not found in file " + TESTCASES_XML);
}
String expectedXml = XML_MAPPER.writeValueAsString(subNode);
expectedXml = unwrapObjectNode(expectedXml);
// Testcalls, e.g. someService.generateXmlData()
String generatedXml = "...";
assertEquals(expectedXml, generatedXml);
};
}
// FIXME: Ugly: Tell XmlMapper to unwrap ObjectNode automatically
private String unwrapObjectNode(String xmlString) {
if(StringUtils.isBlank(xmlString)) {
return xmlString;
}
if(xmlString.startsWith(OBJECT_NODE_START_TAG)) {
xmlString = xmlString.substring(OBJECT_NODE_START_TAG.length());
if(xmlString.endsWith(OBJECT_NODE_CLOSE_TAG)) {
xmlString = xmlString.substring(0, xmlString.length() - OBJECT_NODE_CLOSE_TAG.length());
}
}
return xmlString;
}
}
But the returned expected xml looks like this:
<sizegroup-list>
<sizeGroup>
<id>1</id>
<sizes>
<size>
<technicalSize>38</technicalSize>
<textSize>38</textSize>
<size>
<size>
<technicalSize>705</technicalSize>
<textSize>110cm</textSize>
<size>
</sizes>
</sizeGroup-list>
The former attribute id of the element sizeGroup gets mapped as a sub element and fails my test. How can I tell XmlMapper to keep the attributes of xml elements?
Best regards,
David
i was not able to tell XmlMapper to keep the attributes of xml tags from the loaded xml file. But i have found another way by parsing xml test data with xPath expressions.
A simple String.equals(...) proofed to be unreliable if expected and actual xml contain different whitespaces or xml tag order. Luckily there is a library for comparing xml. XmlUnit!
Additional dependency (seems to be present as transitive dependency as of Spring Boot 2.6.x):
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<!-- version transitive in spring-boot-starter-parent 2.6.7 -->
<version>2.8.4</version>
<scope>test</test>
</dependency>
ResourceUtil.java:
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
public class ResourceUtil {
private static final DocumentBuilderFactory XML_DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
private static final XPathFactory X_PATH_FACTORY = XPathFactory.newInstance();
private ResourceUtil() {}
/** Reads an xml file named after the testcase class (e.g. MyTestcase.class
* -> MyTestcase.xml) and parses the data at the supplied xPath expression. */
public static String xmlData(Class<?> testClass, String xPathExpression) {
return getXmlDocumentAsString(testClass, testClass.getSimpleName() + ".xml", xPathExpression);
}
/** Reads the specified xml file and parses the data at the supplied xPath
* expression. The xml file is expected in the same package/directory as
* the testcase class. */
private static String getXmlDocumentAsString(Class<?> ctxtClass, String fileName, String xPathExpression) {
Document xmlDocument = getXmlDocument(ctxtClass, fileName);
XPath xPath = X_PATH_FACTORY.newXPath();
try {
Node subNode = (Node)xPath.compile(xPathExpression).evaluate(xmlDocument, XPathConstants.NODE);
return nodeToString(subNode.getChildNodes());
} catch (TransformerException | XPathExpressionException var6) {
throw new IllegalArgumentException("Unable to read value of '" + xPathExpression + "' from file " + fileName, var6);
}
}
/** Reads the specified xml file and returns a Document instance of the
* xml data. The xml file is expected in the same package/directory as
* the testcase class. */
private static Document getXmlDocument(Class<?> ctxtClass, String xmlFileName) {
InputStream inputStream = getResourceFile(ctxtClass, xmlFileName);
try {
DocumentBuilder builder = XML_DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
return builder.parse(inputStream);
} catch (SAXException | IOException | ParserConfigurationException var4) {
throw new IllegalStateException("Unable to read xml content from file '" + xmlFileName + "'.", var4);
}
}
/** Returns an InputStream of the specified xml file. The xml file is
* expected in the same package/directory as the testcase class. */
private static InputStream getResourceFile(Class<?> ctxtClass, String fileName) {
String pkgPath = StringUtils.replaceChars(ctxtClass.getPackage().getName(), ".", "/");
String filePath = "/" + pkgPath + "/" + fileName;
URL url = ctxtClass.getResource(filePath);
if (url == null) {
throw new IllegalArgumentException("Resource file not found: " + filePath);
}
return ResourceTestUtil.class.getResourceAsStream(filePath);
}
/** Deserializes a NodeList to a String with (formatted) xml. */
private static String nodeToString(NodeList nodeList) throws TransformerException {
StringWriter buf = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer(getXsltAsResource());
xform.setOutputProperty("omit-xml-declaration", "yes");
xform.setOutputProperty("indent", "no");
for(int i = 0; i < nodeList.getLength(); ++i) {
xform.transform(new DOMSource(nodeList.item(i)), new StreamResult(buf));
}
return buf.toString().trim();
}
/** Returns a Source of an XSLT file for formatting xml data */
private static Source getXsltAsResource() {
return new StreamSource(ResourceTestUtil.class.getResourceAsStream("xmlstylesheet.xslt"));
}
xmlstylesheet.xslt (works for me, you may alter to your preferences):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
MyTestcase.java:
import org.xmlunit.builder.DiffBuilder;
import org.xmlunit.diff.DefaultNodeMatcher;
import org.xmlunit.diff.Diff;
import org.xmlunit.diff.ElementSelectors;
import static ResourceUtil.xmldata;
public class MyTestcase {
#Test
void testcase1() {
// Execute logic to generate xml
String xml = ...
assertXmlEquals(xmlData(getClass(), "/test/testcase1/result"), xml);
}
/** Compare xml using XmlUnit assertion. Expected and actual xml need
* to be equal in content (ignoring whitespace and xml tag order) */
void assertXmlEquals(String expectedXml, String testXml) {
Diff diff = DiffBuilder.compare(expectedXml)
.withTest(testXml)
.ignoreWhitespace()
.checkForSimilar()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText, ElementSelectors.byName))
.build();
assertFalse(diff.fullDescription(), diff.hasDifferences());
}
}
MyTestcase.xml:
<test>
<testcase1>
<result>
<myData>
...
</myData>
</result>
</testcase1>
</test>
Best regards,
David

Skip deserialization of an element and get whole content as a string while xml parsing in java

I have a XML like below:
<content>
<p><b>Node:</b> Some information</p>
</content>
When deserializing this XML, I want to get the content inside p tag as a string.
For example, if I have a java class like below:
#Data
class Content {
TextInParagraph p;
}
#Data
class TextInParagraph {
String text;
}
I should have value of text as "<b>Node:</b> Some information".
Is there a way I can do above using JAXB or Jackson XML parser?
I tried deserializing above in Jackson, but I am getting below exception:
Expected END_ELEMENT, got event of type 1
java.io.IOException: Expected END_ELEMENT, got event of type 1
Sadly, this is not possible with jackson-dataformat-xml.
With JAXB however you can solve this by using a DomHandler
#XmlRootElement(name = "content")
#XmlAccessorType(XmlAccessType.FIELD)
public class Content {
#XmlAnyElement(InnerXmlHandler.class)
private String p;
}
DomHandler
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
public class InnerXmlHandler implements DomHandler<String, StreamResult> {
private static final String START_TAG = "<p>";
private static final String END_TAG = "</p>";
private StringWriter xmlWriter = new StringWriter();
public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
return new StreamResult(xmlWriter);
}
public String getElement(StreamResult rt) {
String xml = rt.getWriter().toString();
int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
int endIndex = xml.lastIndexOf(END_TAG);
return xml.substring(beginIndex, endIndex);
}
public Source marshal(String n, ValidationEventHandler errorHandler) {
try {
String xml = START_TAG + n.trim() + END_TAG;
StringReader xmlReader = new StringReader(xml);
return new StreamSource(xmlReader);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
This works with the sample you provided, but even works with nested <p> tags like:
<content>
<p> This is some <ul><li>list</li></ul> and <p>nested paragraph</p></p>
</content>
However, this works only when the inner HTML/XML is valid. The following will not work and throw an exception like The element type "ul" must be terminated by the matching end-tag "</ul>".
<content>
<p> This is some <ul>invalid xml </p>
</content>
This is because of JAXBs internals which traverses all inner elements although the dom handler is provided.

Map Jackson json attribute to corresponding xml element

I am using Jackson objectMapper to read JSON to JsonNode, Then I am using xmlMapper to serialize this to XML.
I'd like to set an XML attribute value by parsing a JSON attribute with tag "#". Any help would be appreciated. Thanks.
EXAMPLE JSON:
{
"response" : {
"label" : {
"#data" : "someValue"
}
}
}
NEED TO MAP TO XML:
<response>
<label data="someValue" />
</response>
This is what I can get right now:
<response>
<label>
<#data>someValue</#data>
</label>
</response>
CODE:
JsonNode root = objectMapper.readTree(JSON);
xml = xmlMapper.writeValueAsString(root);
well, I found a solution that produces the required output. However, I am not sure if this is an optimal solution, in a sense that it requires custom inner classes to be able to specify the annotations that tell the mappers how to parse.
import java.util.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
public class JSONTest
{
#SuppressWarnings("unchecked")
public static void main(String[] args)
{
try {
String jsonInput = "{ \"response\" : { \"label\" : { \"#data\" : \"someValue\" } }}";
ObjectMapper om = new ObjectMapper();
TypeFactory tf = om.getTypeFactory();
JavaType mapType = tf.constructMapType(HashMap.class, String.class, response.class);
Map<String, response> map = (Map<String, response>)om.readValue(jsonInput, mapType);
XmlMapper xmlMapper = new XmlMapper();
String ss = xmlMapper.writeValueAsString(map.get("response"));
System.out.println(ss);
} catch (Exception e) {
e.printStackTrace();
}
}
public static class response {
public Label label;
}
public static class Label {
#JsonProperty("#data")
#JacksonXmlProperty(isAttribute = true)
public String data;
}
}
output:
<response><label data="someValue"/></response>

JAXB unmarshall element children as plain text [duplicate]

Consider this example -
I have a class called Report that has a field of type Message. The Message class has a field called "body" which is a string. "body" can be any string, but sometimes it contains properly formatted XML content. How can I ensure that when the "body" contains XML content, the serialization takes the form of an XML structure rather than what it gives at present?
Here is the code with the output -
Report class
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "Report")
#XmlType(propOrder = { "message"})
public class Report
{
private Message message;
public Message getMessage() { return message; }
public void setMessage(Message m) { message = m; }
}
Message class
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(propOrder = { "body" })
public class Message
{
private String body;
public String getBody() { return body; }
#XmlElement
public void setBody(String body) { this.body = body; }
}
Main
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class SerializationTest
{
public static void main(String args[]) throws Exception
{
JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Report report = new Report();
Message message = new Message();
message.setBody("Sample report message.");
report.setMessage(message);
jaxbMarshaller.marshal(report, System.out);
message.setBody("<rootTag><body>All systems online.</body></rootTag>");
report.setMessage(message);
jaxbMarshaller.marshal(report, System.out);
}
}
The output is as follows -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
<message>
<body>Sample report message.</body>
</message>
</Report>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
<message>
<body><rootTag><body>All systems online.</body></rootTag></body>
</message>
</Report>
As you can see in the above output, for the second instance of "body", the serialization produced
<body><rootTag><body>All systems online.</body></rootTag></body>
instead of
<body><rootTag><body>All systems online.</body></rootTag></body>
How to solve this problem?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
This use case is mapped using the #XmlAnyElement annotation and specifying a DOMHandler. There appears to be bug when doing this with the JAXB RI, but the following use case works with EclipseLink JAXB (MOXy).
BodyDomHandler
By default a JAXB impleemntation will represent unmapped content as a DOM node. You can leverage a DomHandler to an alternate representation of the DOM, In this case we will represent the DOM as a String.
import java.io.*;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.*;
public class BodyDomHandler implements DomHandler<String, StreamResult> {
private static final String BODY_START_TAG = "<body>";
private static final String BODY_END_TAG = "</body>";
private StringWriter xmlWriter = new StringWriter();
public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
return new StreamResult(xmlWriter);
}
public String getElement(StreamResult rt) {
String xml = rt.getWriter().toString();
int beginIndex = xml.indexOf(BODY_START_TAG) + BODY_START_TAG.length();
int endIndex = xml.indexOf(BODY_END_TAG);
return xml.substring(beginIndex, endIndex);
}
public Source marshal(String n, ValidationEventHandler errorHandler) {
try {
String xml = BODY_START_TAG + n.trim() + BODY_END_TAG;
StringReader xmlReader = new StringReader(xml);
return new StreamSource(xmlReader);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
Message
Below is how you would specify the #XmlAnyElement annotation on your Message class.
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(propOrder = { "body" })
public class Message
{
private String body;
public String getBody() { return body; }
#XmlAnyElement(BodyDomHandler.class)
public void setBody(String body) { this.body = body; }
}
Output
Below is the output from running your SerialziationTest:
<?xml version="1.0" encoding="UTF-8"?>
<Report>
<message>
<body>Sample report message.</body>
</message>
</Report>
<?xml version="1.0" encoding="UTF-8"?>
<Report>
<message>
<body>
<rootTag>
<body>All systems online.</body>
</rootTag>
</body>
</message>
</Report>
For More Information
http://blog.bdoughan.com/2011/04/xmlanyelement-and-non-dom-properties.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
NOTE - Bug in JAXB RI
There appears to be a bug in the JAXB reference implementation, and the example code will result in a stack trace like the following:
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an #XmlRootElement annotation]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:317)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:243)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
at forum12428727.SerializationTest.main(SerializationTest.java:20)
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an #XmlRootElement annotation
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:216)
at com.sun.xml.internal.bind.v2.runtime.LeafBeanInfoImpl.serializeRoot(LeafBeanInfoImpl.java:126)
at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodeProperty.java:100)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:664)
at com.sun.xml.internal.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:141)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:561)
at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:290)
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:462)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:314)
... 3 more
If its only for Marshalling, and to ignore the < and >,
We can use the following:
marshaller.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
#Override
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
writer.write(ac, i, j);
}
});
3 different solutions 1), 2) 3), here below :
1) Following post is a the description of your solution Loresh :
http://anna-safronova.livejournal.com/2524.html?thread=9180
This is still missing limitations details.
With embeeded html, we need a <![CDATA block
JAXB's dependancy
com.sun.xml.bind.marshaller.CharacterEscapeHandler
Needs import jaxb-impl for compilation / and may be required for excution, e.g.
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.4</version>
Limitation : this solution is Container-specific and may not run because of class-loading policy.
2) Another similar approach is JDK's rt.jar dependancy
com.sun.xml.internal.bind.CharacterEscapeHandler
http://theopentutorials.com/tutorials/java/jaxb/jaxb-marshalling-and-unmarshalling-cdata-block/
Same limitation / dependends on target JDK, and some tweaks on Eclipse/Maven are necessary (bad alternative / My opinion)
3) Finally, the best solution was found on another post of Reg Whitton :
https://stackoverflow.com/a/12637295/560410
and this is the detailed reciepe :
http://javacoalface.blogspot.co.uk/2012/09/outputting-cdata-sections-with-jaxb.html
Worked perfect for me !

How do I map several elements to a single class in JAXB

I have following XML on input:
<root>
<response1></response1>
</root>
or
<root>
<response2></response2>
</root>
And there is possibly a lot of response tags each of which I need to map to a single Response class because they have almost the same structure.
Is it easy to do in JAXB?
Thanks.
This could be done with the #XmlElements annotation:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElements({
#XmlElement(name="response1", type=Response.class),
#XmlElement(name="response2", type=Response.class),
#XmlElement(name="response3", type=Response.class)
})
private Response response;
}
http://blog.bdoughan.com/2010/10/jaxb-and-xsd-choice-xmlelements.html
http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html
Well, sure. In XSD file, define a type first:
<xs:complexType name="response">
<!-- define type here -->
</xs:complexType>
Now define your elements using it:
<xs:element name="response1" type="response"/>
<xs:element name="response2" type="response"/>
<!-- and so on and so forth -->
I got it to work this way. It uses an XMLStreamReader as the source, and a StreamReaderDelegate to intercept and rewrite the element names before they reach jaxb.
The main test class:
package grimbo.test.jaxb;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
public class JaxbTest {
public static <T> T unmarshal(Class<T> clazz, InputStream inputStream) throws JAXBException, XMLStreamException,
FactoryConfigurationError {
XMLStreamReader r = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
MyXMLStreamReader my = new MyXMLStreamReader(r);
String packageName = clazz.getPackage().getName();
JAXBContext jc = JAXBContext.newInstance(packageName);
Unmarshaller u = jc.createUnmarshaller();
return (T) u.unmarshal(my);
}
public static void main(String[] args) throws Exception {
String xml1 = "<root>" + "<response1>test1</response1>" + "</root>";
String xml2 = "<root>" + "<response2>test2</response2>" + "</root>";
Object ob = unmarshal(Response.class, new ByteArrayInputStream(xml1.getBytes()));
System.out.println(ob);
ob = unmarshal(Response.class, new ByteArrayInputStream(xml2.getBytes()));
System.out.println(ob);
}
static class MyXMLStreamReader extends StreamReaderDelegate {
public MyXMLStreamReader(XMLStreamReader reader) {
super(reader);
}
public QName getName() {
QName qname = super.getName();
return qname;
}
public String getLocalName() {
String localName = super.getLocalName();
if (localName.matches("response\\d+")) {
return "response";
}
return localName;
}
}
}
The Response class is:
package grimbo.test.jaxb;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "root", namespace = "")
public class Response {
String response;
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
#Override
public String toString() {
return "Response [response=" + response + "]";
}
}
And there's a jaxb.index file in this package too, that declares the Response class:
Response
The output of the test is:
Response [response=test1]
Response [response=test2]
Is this any help?
The easiest thing to do imo would be to make the response element an unbounded list in your schema then once you have created your bindings you can iterate throught the list of response nodes.
I tried to map multiple tag to single class using JAXB with same format mention above.
Now define your elements using it:
<xs:element name="response1" type="response"/>
<xs:element name="response2" type="response"/>
<!-- and so on and so forth -->
While unmarshalling JAXB validates the XML(format) with response class format mentioned in XSD file ,but its is giving me JAXB.element class object instead of response object.
Please suugest with answer..

Categories