How to use hashmap properties with JAXB? - java

I've been fiddling around with JAXB for a while now, I need to generate xml like below
<Root attr1="" attr2="" .. attrn="" >
<CNode attr1="" attr2="" />
.
.
.
<CNode .. />
</Root>
The attributes of Root element is dynamic and would come from either a properties file or a template. What is the best way to get it into the structure as shown above? I'm using hashmaps for dynamic variables and then tried mapping it with XmlJavaTypeAdapter, the best I could do is
<Root>
<Attribs>
<entry key="attr1">Value</entry>
</Attribs>
<CNode .. />
</Root>
Is there a way in jaxb to say use hashmap's key as the attribute name and the value for that key as the value for that attribute in xml? Or if you think there is a better way to do it, I'm open for suggestions. I'm quite thinking about using jaxb's marshaller to add the Root node separately. However it would be nicer if I can just use jaxb's adapter. Thanks!

#XmlAnyAttribute is along the lines of what you need:
Root
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
#XmlRootElement(name="Root")
public class Root {
private Map<QName, String> extension;
private List<CNode> cnodes;
#XmlAnyAttribute
public Map<QName, String> getExtension() {
return extension;
}
public void setExtension(Map<QName, String> extension) {
this.extension = extension;
}
#XmlElement(name="CNode")
public List<CNode> getCnodes() {
return cnodes;
}
public void setCnodes(List<CNode> cnodes) {
this.cnodes = cnodes;
}
}
CNode
import java.util.Map;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.namespace.QName;
public class CNode {
private Map<QName, String> extension;
#XmlAnyAttribute
public Map<QName, String> getExtension() {
return extension;
}
public void setExtension(Map<QName, String> extension) {
this.extension = extension;
}
}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<Root att1="A" att2="B">
<CNode att3="C" att4="D"/>
<CNode att5="E" att6="F"/>
</Root>

Related

Reading my XML with JAXB

I have an xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<measures>
<measure isapplicationaggregated="true" errorseverity="none" servicecontext="SERVER" userdefined="false" id=".NET % Time in Jit" calculatepercentiles="false" createdtimestamp="1478709202942" errortype="none" rate="purepath" description="Percentage of elapsed time spent in JIT compilation since the last JIT compilation phase." ischartable="true" metricid=".NET % Time in Jit" measuretype="PerfMonMeasure" isaggregated="false" metricgroupid=".NET Common Language Runtime" displayaggregations="7" calculatebaseline="false" displayunit="percent">
<perfmonperformancecounter performanceobject=".NET CLR Jit" instance="{monitored_process}" performancecounter="% Time in Jit" />
<color color.blue="64" color.green="0" color.red="64" />
</measure>
<measure isapplicationaggregated="true" errorseverity="none" servicecontext="SERVER" userdefined="false" id=".NET Garbage Collection (# Gen 0)" calculatepercentiles="false" createdtimestamp="1478709202942" errortype="none" rate="purepath" description="Number of times the generation 0 objects were garbage collected (Gen 0 GC) per interval." ischartable="true" metricid=".NET Garbage Collection (# Gen 0)" measuretype="PerfMonMeasure" isaggregated="false" metricgroupid=".NET Common Language Runtime" displayaggregations="31" calculatebaseline="false" displayunit="number">
<perfmonperformancecounter performanceobject=".NET CLR Memory" instance="{monitored_process}" performancecounter="# Gen 0 Collections" />
<color color.blue="64" color.green="192" color.red="128" />
</measure>
</measures>
I need to translate it using the JAXB reader except it keeps saying it cannot read it.
I only need the userdefined , id , and measuretype properties from the measure object.
The code below is what I have so far:
XML
#XmlRootElement(name = "measures")
public class MeasureListWrapper {
private List<Property> measureProperties = new ArrayList<Property>();
#XmlElement(name="measure")
public List<Property> getMeasures() {
return measureProperties;
}
}
MainApp:
JAXBContext context = JAXBContext.newInstance(MeasureListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
// Reading XML from the file and unmarshalling.
MeasureListWrapper wrapper = (MeasureListWrapper) um.unmarshal(file);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "file:///C:/Users/mydesk/Desktop/FirstXSD.xml");
marshaller.marshal(wrapper, System.out);
I am new to JAXB and can't get this to work. Really I just need to export the preferred properties to a text file after I pull them from this xml.
I would also like to store the ID's and measuretypes to display in a table in my applet window.
Any help?
Thanks!
This worked for me:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MeasureParser {
#XmlRootElement(name = "measure")
public static class Measure {
#XmlAttribute(name = "id")
private String id;
#XmlAttribute(name = "measuretype")
private String measureType;
#XmlAttribute(name = "userdefined")
private boolean userDefined;
}
#XmlRootElement(name = "measures")
public static class MeasureListWrapper {
private List<Measure> measureProperties = new ArrayList<>();
#XmlElement(name = "measure")
public List<Measure> getMeasures() {
return measureProperties;
}
}
public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(MeasureListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
// Reading XML from the file and unmarshalling.
MeasureListWrapper wrapper = (MeasureListWrapper) um.unmarshal(new File("test.xml"));
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "file:///C:/Users/mydesk/Desktop/FirstXSD.xml");
marshaller.marshal(wrapper, System.out);
}
}

XML to POJO Mapping

I have a service that does the following:
receives different XML requests
turns them into JIBX-generated Java objects
maps the JIBX-generated Java objects into POJOs
sends the POJOs to another service
gets a POJO response back
maps POJO back into JIBX-generated Java objects
turns JIBX-generated Java objects back into XML
returns XML to client.
I'd like to make this process more efficient. Can anyone suggest how? Can JIBX map directly into my POJOs?
Yes Jibx can map directly to your POJOs using Jibx mapping files. I think the below link will be very helpful to understand Jibx binding.
Jibx Introduction
In this you needed library which is available in the url(4shared.com) commented in comments.
package com.xml.Sample.MainP;
import java.io.File;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import com.xml.Sample.Actions.XMLAction;
import com.xml.Sample.Model.States;
public class Retrieve {
public static String XMLModelName = "com.xml.Sample.Model.States";
private static String cities = "E:\\Webeclipseworkspace\\Samples\\src\\Srates.xml";
public static void main(String[] args) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
File f = new File(cities);
Document doc = db.parse(f);
doc.getDocumentElement().normalize();
XMLAction xmla = new XMLAction();
List<States> listXML = xmla.readData(XMLModelName, doc);
// System.out.println(listXML);
String xmlData = xmla.writtingData(listXML);
System.out.println(xmlData);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
}
}
package com.xml.Sample.Model;
import com.xml.Sample.XMLAnn.XMLColumn;
import com.xml.Sample.XMLAnn.XMLReport;
#XMLReport(reportName = "row")
public class Directory {
private String city_id;
private String city_name;
private String state_id;
#XMLColumn(label = "city_id")
public String getCity_id() {
return city_id;
}
public void setCity_id(String city_id) {
this.city_id = city_id;
}
#XMLColumn(label = "city_name")
public String getCity_name() {
return city_name;
}
public void setCity_name(String city_name) {
this.city_name = city_name;
}
#XMLColumn(label = "state_id")
public String getState_id() {
return state_id;
}
public void setState_id(String state_id) {
this.state_id = state_id;
}
}
Here I Created Own Library For Converting Pojo classes to xml and xml to pojo classes.
Use Below Link(4Shared.com) at Comments to download Library to add for The Above Code.
String(XML in String) to List
1. FolderItem.java
<code>
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
#XmlAccessorType(XmlAccessType.FIELD)
public class FolderItem {
long itemId ;
String itemName;
String itemType;
String description;
String[] tags;
String path;
/* setters and getters
Annotations not required*/
}
</code>
2. FolderItems.java
<code>
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class FolderItems {
#XmlElement
private List<FolderItem> folderItem;
/* setter and getter */
}
</code>
3. Testing--main method
<code>
class Test{
public static void main(String[] args) throws Exception {
FolderItems f = (FolderItems)strToVo(content, FolderItems.class);
System.out.println(f);
}
static Object strToVo(String content, Class c) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = jc.createUnmarshaller();
return unmarshaller.unmarshal(new InputSource(new StringReader(content)));
}
}
</code>
4. XML in String
<code>
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<FolderItems>
<folderItem>
<description>Lapse notice invoice for additional interests/additional insureds</description>
<itemId>480004439</itemId>
<itemName>Lapse_Invoice_AI</itemName>
<itemType>application/x-thunderhead-ddv</itemType>
<path>/Templates/Billing Center/Lapse_Invoice_AI</path>
<tags></tags>
</folderItem>
</FolderItems>
</code>

JAXB marshlling is not ignoring namespace

I have spent some time to investigate what is the problem but I couldn't solve it. When I unmarshal below XML and marshal back I see different XML.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<one>test</one>
<three>\MySG\test.jsp</three>
<two>
<st>
<seeta>
<Source>
<problemtag xmlns="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92">
<p>deploy_test_page_renderingMetadata</p>
</problemtag>
</Source>
</seeta>
<Template id="tcm:1-63-32" title="Smart Compound Component Template"/>
<Publication id="tcm:0-1-1" title="Publication"/>
</st>
</two>
</root>
In the above xml only one tag (first one) expected remaining all (including namespace) are unexpected elements. Another application sends the above XML.
My Mapping are like this
package com.seeta.xml;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name="one")
private String one;
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
#XmlElement(name="three")
private String three;
#XmlAnyElement
private List<Object> remaining = new ArrayList<Object>();
public String getThree() {
return three;
}
public void setThree(String three) {
this.three = three;
}
public List<Object> getRemaining() {
return remaining;
}
public void setRemaining(List<Object> remaining) {
this.remaining = remaining;
}
public String toString() {
return String.format("One [%s]-> Number of remaing elements [%d]-> three [%s]", one, remaining.size(), three);
}
}
Here is my simple code
package com.seeta.xml;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLDecoder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class JaxbSample {
public Document getDOMDocument(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
if (inputStream != null) {
return documentBuilder.parse(new InputSource(inputStream));
} else {
return documentBuilder.newDocument();
}
}
public Root unmarshall(Document document) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(document);
return root;
}
public Document marshall(Root root) throws JAXBException, ParserConfigurationException, SAXException, IOException {
JAXBContext context = JAXBContext.newInstance(Root.class);
Marshaller marshaller = context.createMarshaller();
Document document = getDOMDocument(null);
marshaller.marshal(root, document);
return document;
}
private String transform(Document document) throws TransformerException {
StringWriter sw = new StringWriter();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(document), new StreamResult(sw));
return sw.toString();
}
public void testUnmarshallMarshallUsingDocument() throws ParserConfigurationException, SAXException, IOException, JAXBException, TransformerException {
InputStream inputStream = this.getClass().getResourceAsStream("jaxb.xml");
Document document = getDOMDocument(inputStream);
Root root = unmarshall(document);
Document documentAfterMarshal = marshall(root);
String output = transform(documentAfterMarshal);
System.out.println(output);
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, JAXBException, TransformerException {
JaxbSample jaxbTest = new JaxbSample();
jaxbTest.testUnmarshallMarshallUsingDocument();
}
}
output is
<root>
<one>test</one>
<three>\MySG\test.jsp</three>
<two>
<st>
<seeta>
<Source>
<problemtag:problemtag xmlns="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92" xmlns:problemtag="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92">
<p>deploy_test_page_renderingMetadata</p>
</problemtag:problemtag>
</Source>
</seeta>
<Template id="tcm:1-63-32" title="Smart Compound Component Template"/>
<Publication id="tcm:0-1-1" title="Publication"/>
</st>
</two>
</root>
And also I tried following
I tried with NamespacePrefixMapper. I can able to give different namespace but not empty(""). I don't want any namespace at all.
new NamespacePrefixMapper() {
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return "";
}
};
We don't have any xsd ( at least I don't know) in our project for trying unqualified thing
I really didn't understand QName thing
If all you want is to preserve the unused elements and marshall them back, I think you ought to be able to do something like this:
#XmlRootElement(name="Root")
#XmlAccessorType(XmlAccessType.FIELD)
class Root {
#XmlElement(name="One")
private String one;
#XmlAnyElement
private List<Any> otherElements;
}
class AnyAdapter extends XmlAdapter<Element,Any> {
#Override
public Any unmarshal(Element element) throws Exception {
return new Any(element);
}
#Override
public Element marshal(Any any) throws Exception {
return any.element;
}
}
#XmlJavaTypeAdapter(AnyAdapter.class)
class Any {
Element element;
Any(Element element) {
this.element = element;
}
}
I don't want any namespace at all.
You won't be able to accomplish this with JAXB alone. The #XmlAnyElement tells the unmarshaller to dump the elements that it can't process into your list. Those elements have namespaces attached. When you then marshal those elements, they'll be written with their namespaces.
One option is for you to parse the incoming XML with a namespace-unaware DOM parser, then unmarshall it using the DOM tree. There's an example of this in the Unmarshaller JavaDoc (which uses a namespace-aware parser; it should be obvious what to change to make it namespace-unaware).
I really didn't understand QName thing
Do you mean that you don't understand why the output is a qualified name, or why it picked the particular prefix? Or what QNames mean?
It's a qualified name because that's the most unambiguous way to represent the element.
I can't tell you why it picked this particular prefix; the JAXP serializer picks short names like "ns1", "ns2", and so on.

XmlPath mapping problems using eclipselink MOXy

I don't see why the XmlPath mappings I have made below are coming out as null. Is there something wrong with my syntax? I used similar syntax elsewhere without problem.
Thanks for any clues.. John
<clip lane="-1" offset="2591065664/720000s" name="Music" duration="22304160/240000s" start="176794/48000s" enabled="0" format="r5">
<adjust-volume amount="1dB">
<param name="amount">
<fadeIn type="easeIn" duration="1220/262144s"/>
</param>
</adjust-volume>
<audio ref="r9" name="VoiceOver-26 - audio" duration="4639346/48000s" role="dialogue"/>
</clip>
#XmlRootElement(name = "clip")
#XmlAccessorType(XmlAccessType.FIELD)
public class Clip extends StoryElement {
#XmlPath("adjust-volume/#amount")
#XmlJavaTypeAdapter(DecibelValueAdapter.class)
private Double adjustVolume;
#XmlPath("adjust-volume/param[#name='amount']/fadeIn/#duration")
#XmlJavaTypeAdapter(TimeValueAdapter.class)
private TimeValue fadeIn;
#XmlPath("adjust-volume/param[#name='amount']/fadeOut/#duration")
#XmlJavaTypeAdapter(TimeValueAdapter.class)
private TimeValue fadeOut;
I have not been able to reproduce the issue that you are seeing using EclipseLink 2.4.0. Below is what I have tried.
Clip
Your mappings appear to be ok.
package forum11937980;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "clip")
#XmlAccessorType(XmlAccessType.FIELD)
public class Clip extends StoryElement {
#XmlPath("adjust-volume/#amount")
#XmlJavaTypeAdapter(DecibelValueAdapter.class)
private Double adjustVolume;
#XmlPath("adjust-volume/param[#name='amount']/fadeIn/#duration")
#XmlJavaTypeAdapter(TimeValueAdapter.class)
private TimeValue fadeIn;
#XmlPath("adjust-volume/param[#name='amount']/fadeOut/#duration")
#XmlJavaTypeAdapter(TimeValueAdapter.class)
private TimeValue fadeOut;
}
jaxb.properties
Do you have a jaxb.properties file in the same package as your domain model with the following entry to specify MOXy as your JAXB provider?
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
input.xml
<clip lane="-1" offset="2591065664/720000s" name="Music" duration="22304160/240000s"
start="176794/48000s" enabled="0" format="r5">
<adjust-volume amount="1dB">
<param name="amount">
<fadeIn type="easeIn" duration="1220/262144s" />
<fadeOut duration="I/Added/This"/>
</param>
</adjust-volume>
<audio ref="r9" name="VoiceOver-26 - audio" duration="4639346/48000s"
role="dialogue" />
</clip>
Demo
package forum11937980;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Clip.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11937980/input.xml");
Clip clip = (Clip) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(clip, System.out);
}
}
Output
Below is the output from running the demo code. Note that only the mapped portions from the input appear in the output.
<?xml version="1.0" encoding="UTF-8"?>
<clip>
<adjust-volume amount="1.0dB">
<param name="amount">
<fadeIn duration="1220/262144s"/>
<fadeOut duration="I/Added/This"/>
</param>
</adjust-volume>
</clip>
SUPPORTING FILES
Below are the rest of the files needed to make this example run:
StoryElement
package forum11937980;
public class StoryElement {
}
DecibalValueAdapter
package forum11937980;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DecibelValueAdapter extends XmlAdapter<String, Double> {
#Override
public String marshal(Double v) throws Exception {
return String.valueOf(v) + "dB";
}
#Override
public Double unmarshal(String v) throws Exception {
return Double.valueOf(v.substring(0, v.length() - 2));
}
}
TimeValue
package forum11937980;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class TimeValue {
#XmlValue
private String value;
}
TimeValueAdapter
package forum11937980;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class TimeValueAdapter extends XmlAdapter<TimeValue, TimeValue> {
#Override
public TimeValue marshal(TimeValue v) throws Exception {
return v;
}
#Override
public TimeValue unmarshal(TimeValue v) throws Exception {
return v;
}
}

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