I have used JAXB to parse an XML.How to get a particular element(ie a child node) through JAXB xml parsing without parsing that element as node.
<?xml version="1.0" encoding="UTF-8"?>
<Header>
<From>
<Credential
domain="NetworkId"><Identity>ANXXXNNN</Identity>
</Credential>
</From>
<To>
<Credential
domain="NetworkId"><Identity>ANNNXXXXXT</Identity>
</Credential>
</To>
<To>
<Credential
domain="NetworkId"><Identity>BNNXXXT</Identity>
</Credential>
</To>
</Header>
I have done unmarshalling like this,It works fine.For performance,I dont want the elements as node.Is there anyother way to do?
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc;
doc = db.parse(file);
NodeList node = (NodeList)doc.getElementsByTagName("TO");
JAXBElement<ToType> element = jaxbUnmarshaller.unmarshal(node.item(0),ToType.class);
Object model is like
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ToType", propOrder = {
"credential"
})
public class ToType {
#XmlElement(name = "Credential", required = true)
protected CredentialType credential;
public CredentialType getCredential() {
return credential;
}
public void setCredential(CredentialType value) {
this.credential = value;
}
}
A StAX (JSR-173) parser (included in the JDK/JRE starting with Java SE 6) can be used. Then you can advance the XMLStreamReader to the child node and unmarshal from there.
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("src/forum14358769/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
// Advance to the "To" element.
while(xsr.hasNext()) {
if(xsr.isStartElement() && "To".equals(xsr.getLocalName())) {
break;
}
xsr.next();
}
// Unmarshal from the XMLStreamReader that has been advanced
JAXBContext jc = JAXBContext.newInstance(ToType.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
ToType toType = unmarshaller.unmarshal(xsr, ToType.class).getValue();
}
}
For More Information
http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html
You will have to do following code for doing JAXB Unmarshalling:
unmarshaler.unmarshal(source);
This will return you the instance of class which you would have generated using xjc command.
Then you can access any property using bean methods.
Related
I have a situation where I'd like to start using an XML Schema to validate documents that, until now, have never had a schema definition. As such, the existing documents I'd like to validate do not have any xmlns declaration in them.
I have no problem successfully validating a document which does include the xmlns declaration, but I'd also like to be able to validate those documents without such a declaration. I was hoping for something like this:
DocumentBuilderFactory dbf = ...;
dbf.setSchema(... my schema for namespace "foo:bar"...);
dbf.setValidating(false);
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setDefaultNamespace("foo:bar");
Document doc = db.parse(input);
There is no such method DocumentBuilder.setDefaultNamespace and so the schema validation is not performed when loading documents of this type.
Is there any way to force the namespace for a document if one is not set? Or does that require essentially parsing the XML without regard to schema, checking for an existing namespace, adjusting it, then re-validating the document with the schema?
I'm currently expecting the parser to perform validation during parsing, but I have no problem parsing first and then validating afterward.
UPDATE 2021-01-13
Here is a concrete example of what I'm trying to do, as a JUnit test case.
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.junit.Assert;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class XMLSchemaTest
{
private static final String XMLNS = "http://www.example.com/schema";
private static final String schemaDocument = "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" targetNamespace=\"" + XMLNS + "\" xmlns:e=\"" + XMLNS + "\" elementFormDefault=\"qualified\"><xs:element name=\"example\" type=\"e:exampleType\" /><xs:complexType name=\"exampleType\"><xs:sequence><xs:element name=\"test\" type=\"e:testType\" /></xs:sequence></xs:complexType><xs:complexType name=\"testType\" /></xs:schema>";
private static Document parse(String document) throws SAXException, ParserConfigurationException, IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
SchemaFactory sf = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Source[] sources = new Source[] {
new StreamSource(new StringReader(schemaDocument))
};
Schema schema = sf.newSchema(sources);
dbf.setSchema(schema);
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setErrorHandler(new MyErrorHandler());
return db.parse(new InputSource(new StringReader(document)));
}
#Test
public void testConformingDocumentWithSchema() throws Exception {
String testDocument = "<example xmlns=\"" + XMLNS + "\"><test/></example>";
Document doc = parse(testDocument);
//Assert.assertEquals("Wrong document XML namespace", XMLNS, doc.getNamespaceURI());
Element root = doc.getDocumentElement();
Assert.assertEquals("Wrong root element XML namespace", XMLNS, root.getNamespaceURI());
Assert.assertEquals("Wrong element name", "example", root.getLocalName());
Assert.assertEquals("Wrong element name", "example", root.getTagName());
}
#Test
public void testConformingDocumentWithoutSchema() throws Exception {
String testDocument = "<example><test/></example>";
Document doc = parse(testDocument);
//Assert.assertEquals("Wrong document XML namespace", XMLNS, doc.getNamespaceURI());
Element root = doc.getDocumentElement();
Assert.assertEquals("Wrong root element XML namespace", XMLNS, root.getNamespaceURI());
Assert.assertEquals("Wrong element name", "example", root.getLocalName());
Assert.assertEquals("Wrong element name", "example", root.getTagName());
}
#Test
public void testNononformingDocumentWithSchema() throws Exception {
String testDocument = "<example xmlns=\"" + XMLNS + "\"><random/></example>";
try {
parse(testDocument);
Assert.fail("Document should not have parsed properly");
} catch (Exception e) {
System.out.println(e);
// Expected
}
}
#Test
public void testNononformingDocumentWithoutSchema() throws Exception {
String testDocument = "<example><random/></example>";
try {
parse(testDocument);
Assert.fail("Document should not have parsed properly");
} catch (Exception e) {
System.out.println(e);
// Expected
}
}
public static class MyErrorHandler implements ErrorHandler {
#Override
public void warning(SAXParseException exception) throws SAXException {
System.err.println("WARNING: " + exception);
}
#Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
#Override
public void fatalError(SAXParseException exception) throws SAXException {
System.err.println("FATAL: " + exception);
}
}
}
All of the tests pass except for testConformingDocumentWithoutSchema. I think this is kind of expected, as the document declares no namespace.
I'm asking how the test can e changed (but not the document itself!) so that I can validate the document against a schema that was not actually declared by the document.
I pounded on this for a while, and I was able to come up with a hack that works. It may be possible to do this more elegantly (which was my original question), and it also may be possible to do this with less code, but this was what I was able to come up with.
If you look at the JUnit test case in the question, changing the "parse" method to the following (and adding XMLNS as the second argument to all calls to parse) will allow all tests to complete:
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
...
private static Document parse(String document, String namespace) throws SAXException, ParserConfigurationException, IOException {
SchemaFactory sf = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
Source[] sources = new Source[] {
new StreamSource(new StringReader(schemaDocument))
};
Schema schema = sf.newSchema(sources);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setSchema(schema);
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
ErrorHandler errorHandler = new MyErrorHandler();
db.setErrorHandler(errorHandler);
try {
return db.parse(new InputSource(new StringReader(document)));
} catch (SAXParseException spe) {
// Just in case this was a problem with a missing namespace
// System.out.println("Possibly recovering from SPE " + spe);
// New DocumentBuilder without the schema
dbf.setSchema(null);
db = dbf.newDocumentBuilder();
db.setErrorHandler(errorHandler);
Document doc = db.parse(new InputSource(new StringReader(document)));
if(null != doc.getDocumentElement().getNamespaceURI()) {
// Namespace URI was set; this is a fatal error
throw spe;
}
// Override the namespace on the Document + root element
doc.getDocumentElement().setAttribute("xmlns", namespace);
// Serialize the document -> String to start over again
DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation();
LSSerializer lsSerializer = domImplementation.createLSSerializer();
LSOutput lsOutput = domImplementation.createLSOutput();
lsOutput.setEncoding("UTF-8");
StringWriter out = new StringWriter();
lsOutput.setCharacterStream(out);
lsSerializer.write(doc, lsOutput);
String converted = out.toString();
// Re-enable the schema
dbf.setSchema(schema);
db = dbf.newDocumentBuilder();
db.setErrorHandler(errorHandler);
return db.parse(new InputSource(new StringReader(converted)));
}
}
This works by catching SAXParseException and, because SAXParseException doesn't give up any of its details, assuming that the problem might be due to a missing XML namespace declaration. I then re-parse the document without the schema validation, add a namespace declaration to the in-memory Document, then serialize the Document to String and re-parse the document with the schema validation re-enabled.
I tried to do this just by setting the XML namespace and then using Schema.newValidator().validate(new DOMSource(doc)), but this failed validation every time for me. Running through the serializer got around that problem.
I'm working on a project that has no schema and I have to parsing the xml response manually.
My problem is i can't get some value using the xml annotation.
For example , the xml is like:
<?xml version='1.0' encoding='UTF-8' ?>
<autnresponse>
<action>QUERY</action>
<response>SUCCESS</response>
<responsedata>
<autn:numhits>7</autn:numhits>
</responsedata>
</autnresponse>
And the java class is :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "autnresponse")
public class AutonomyResponse {
private String action;
private String response;
private ResponseData responsedata;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responsedata")
public class ResponseData {
#XmlElement(name = "numhits",namespace = "autn")
private String numhits;
#XmlElement(name = "totalhits")
private String totalhits;
}
I can get the action and the response, but can't get the numhits in the responsedata,
Can anyone tell me how to handle the <autn:numhits> using annotation?
Too much Thanks !!!
Another issue is : I have multi <autn:numhits> in the responsedata....how can i get all the value in the Java code.
--> I solve this multi same tags, just set List and the annotation will automatically generate the list
The fact is autn - is only prefix, not namespace. For correct processing of the XML document, namespace must be declared.
Right namespace declaration:
<?xml version='1.0' encoding='UTF-8' ?>
<autnresponse xmlns:autn="http://namespace.here">
<action>QUERY</action>
<response>SUCCESS</response>
<responsedata>
<autn:numhits>7</autn:numhits>
</responsedata>
</autnresponse>
You also need to change the annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responsedata")
public class ResponseData {
#XmlElement(name = "numhits",namespace = "http://namespace.here")
private String numhits;
#XmlElement(name = "totalhits")
private String totalhits;
}
And finnaly advice for you. If you have a xsd scheme for this xml document, use the XJC utilit for java code generation.
http://docs.oracle.com/javaee/5/tutorial/doc/bnbah.html
JAXB and other XML processors that are capable of processing XML Schema are going to treat everything before a : as a namespace prefix. If the colon is then you can do the following.
Java Model
You need to specify that your element name contains the : character.
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseData {
#XmlElement(name = "autn:numhits")
private String numhits;
private String totalhits;
}
Demo
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.XMLReader;
public class Demo {
public static void main(String[] args) throws Exception {
// Create a SAXParser that is not namespace aware
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(AutonomyResponse.class);
// Instead of Unmarshaller we will use an UnmarshallerHandler
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
// Do a SAX parse with the UnmarshallerHanlder as the ContentHandler
xr.setContentHandler(unmarshallerHandler);
xr.parse("src/forum20062536/input.xml");
// Get the result of the unmarshal
AutonomyResponse autonomyResponse = (AutonomyResponse) unmarshallerHandler.getResult();
// Marshal the object back to XML
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(autonomyResponse, System.out);
}
}
I have
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
#XmlType(name = "course")
public class Course implements Resource
...
#XmlElementWrapper(name="subcourses")
#XmlElement(name="course")
List<Xlink> subcourses; //!?
and Xlink class, which works fine in inline variable.
public class Xlink
{
private String href;
private String value;
#XmlAttribute(namespace = "http://www.w3.org/1999/xlink")
public String getHref()
{
return href;
}
public void setHref(String href)
{
this.href = href;
}
#XmlValue
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
}
for an XML input of
<atom:content atom:type="xml" xsi:type="course">
...
<subcourses>
<course xlink:href="course1">Some course</course>
<course xlink:href="course2">other course</course>
And subcourses refuses to be unmarshalled (without any exception being thrown).
Note: MOXy is unfortunately not an option.
Edit: new marshalled object
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course ns2:href="Some href">some value</course>
<course ns2:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns3:content>
Edit2: after some experimentation with unmarshalling and marshalling a test object I have discovered that I need to define xmlns namespace in the header of the content to match xlink:href= like xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am getting the Course element from inside a wrapper class that is parsed out by resteasy. Thus the resulting class does not carry over the namespace information.
I somehow need to force JAXB to understand that xmlns:xlink="http://www.w3.org/1999/xlink" applies to the course elements, but after an hour of google I am at a loss.
Edit3: I am getting my object from
https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom/jaxb/Entry.java
which is used on the server counterpart. Which in turn is a part of
https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom/jaxb/Feed.java
Relevant parts of my unmarshalling code are:
Feed f = r.readEntity(Feed.class);
out.addAll(unmarshaller.Unmarshal(f.getEntries(), clazz));
where r is a javax.ws.rs.core.Response. And the unmarshaller
public List<T> Unmarshal(List<Entry> entries, Class clazz)
{
List<T> out = new ArrayList<T>();
T instance;
for (Entry e : entries)
{
try
{
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarsh = context.createUnmarshaller();
instance = (T) unmarsh.unmarshal((Node) e.getContent());
Since this is my first tangle with this technology, it is entirely possible that this code is 'wtf'.
When you annotate the field (instance variable) be sure to put #XmlAccessorType(XmlAccessType.FIELD) on your class.
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
#XmlAccessorType(XmlAccessType.FIELD)
public class Course implements Resource {
#XmlElementWrapper(name = "subcourses")
#XmlElement(name = "course")
List<Xlink> subcourses;
}
Then make sure your XML input is correctly namespace qualified. Your input document should look something like the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:content xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
With my updated Course class, your Xlink class and a properly namespace qualified XML document the following demo code worked perfectly for me.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17766166/input.xml");
Course course = (Course) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
UPDATE #1
Edit2: after some experimentation with unmarshalling and marshalling a
test object I have discovered that I need to define xmlns namespace in
the header of the content to match xlink:href= like
xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am
getting the Course element from inside a wrapper class that is parsed
out by resteasy. Thus the resulting class does not carry over the
namespace information.
The best place to fix your issue is where you extract the fragment you wish to unmarhal. Below is a strategy you can use with StAX.
input.xml
Below is a sample XML document where the namespace information is defined above the fragment you wish to unmarshal.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<bar>
<atom:content>
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
</bar>
</foo>
Demo
Below we will use a StAX XMLStreamReader to navigate to the target fragment. We will have our JAXB implementation unmarshal this fragment. This way all the namespace information is preserved.
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource source = new StreamSource("src/forum17766166/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
while(xsr.hasNext()) {
if(xsr.isStartElement() && "content".equals(xsr.getLocalName())) {
break;
}
xsr.next();
}
Unmarshaller unmarshaller = jc.createUnmarshaller();
Course course = (Course) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
<subcourses>
<course ns2:href="Some href">some value</course>
<course ns2:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns3:content>
UPDATE #2
If you can't produce a better XML fragment as described in UPDATE #1, below is how you could fix the XML fragment you currently have.
NamespaceFilter
You could use a SAX XMLFilter to fix up your XML document.
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class NamespaceFilter extends XMLFilterImpl {
private static final String ATOM_URI = "http://www.w3.org/2005/Atom";
private static final String XLINK_URI = "http://www.w3.org/1999/xlink";
#Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
if("atom:content".equals(qName)) {
super.startElement(ATOM_URI, "content", qName, atts);
} else if("course".equals(qName)) {
AttributesImpl modifiedAtts = new AttributesImpl();
modifiedAtts.addAttribute(XLINK_URI, "href", "xlink:href", null, atts.getValue(0));
super.startElement(uri, localName, qName, modifiedAtts);
} else {
super.startElement(uri, localName, qName, atts);
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("atom:content".equals(qName)) {
super.endElement(ATOM_URI, "content", qName);
} else {
super.endElement(uri, localName, qName);
}
}
}
Demo
Below is how you can leverage the XmlFilter with JAXB:
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Course.class);
// Create the XMLFilter
XMLFilter filter = new NamespaceFilter();
// Set the parent XMLReader on the XMLFilter
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
filter.setParent(xr);
// Set UnmarshallerHandler as ContentHandler on XMLFilter
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller
.getUnmarshallerHandler();
filter.setContentHandler(unmarshallerHandler);
// Parse the XML
InputSource xml = new InputSource("src/forum17766166/input.xml");
filter.parse(xml);
Course course = (Course) unmarshallerHandler.getResult();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
For More Information
http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html
UPDATE #3
Below is a simplified version of your example code where everything works. Maybe there is something different in your code it will help you find.
Entry
import javax.xml.bind.annotation.*;
#XmlRootElement(namespace="http://www.w3.org/2005/Atom")
#XmlAccessorType(XmlAccessType.FIELD)
public class Entry<T> {
#XmlElement(namespace = "http://www.w3.org/2005/Atom")
#XmlSchemaType(name = "atomInlineOtherContent")
private T content;
public T getContent() {
return content;
}
}
input.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:entry xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
<atom:content>
<code>SOME CODE</code>
<name>name</name>
<subcourses>
<course xlink:href="Some href">some value</course>
<course xlink:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</atom:content>
</atom:entry>
Demo
import java.io.File;
import javax.xml.bind.*;
import org.w3c.dom.Node;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Entry.class, Course.class);
// Unmarshal Entry
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum17766166/input.xml");
Entry entry = (Entry) unmarshaller.unmarshal(xml);
// Unmarshal Course
Node contentNode = (Node) entry.getContent();
Course course = (Course) unmarshaller.unmarshal(contentNode);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(course, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<ns0:content xmlns:ns1="http://www.w3.org/1999/xlink" xmlns:ns0="http://www.w3.org/2005/Atom">
<subcourses>
<course ns1:href="Some href">some value</course>
<course ns1:href="sdsdg">sdfhdfhdhdh</course>
</subcourses>
</ns0:content>
When trying to unmarshall some XML into a POJO using EclipseLink MOXy I'm getting a FileNotFoundException where it's looking for the document's DTD as a relative path.
Exception in thread "main" org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[java.io.FileNotFoundException: C:\Users\deejay\Documents\workspace-sts-3.0.0.RELEASE\moxy-test\ieee_idams_exchange.dtd (The system cannot find the file specified)]
at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:761)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:682)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:665)
at com.mendeley.services.utility.EclipseLinkMarshaller.load(EclipseLinkMarshaller.java:29)
at com.mendeley.MoxyTest.main(MoxyTest.java:31)
I'm providing "externalized metadata" as per this example, so I've no idea why it even needs a DTD. If I could get it to ignore the DTD, or not try and resolve it, that'd be great.
You could unmarshal from an XMLStreamReader that has DTD support disabled:
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("input.xml"));
Unmarshaller unmarshaller = jc.createUnmarshaller();
Customer customer = (Customer) unmarshaller.unmarshal(xsr);
}
}
Extra
If you want to write the DTD declaration you could do the following:
XMLOutputFactory xof = XMLOutputFactory.newFactory();
XMLStreamWriter xsw = xof.createXMLStreamWriter(System.out);
xsw.writeDTD("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(html, xsw);
xsw.close();
i have one requirement to get the data from the xml.
String res;
the data will be in the string res as follows.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<id>QZhx_w1eEJ</id>
<first-name>pratap</first-name>
<last-name>murukutla</last-name>
</person>
i have to get the id and the first-name and last-name from this data and has to be stored in the variables id,first-name,last-name
how to access the xml to get those details.
You could use JAXB (JSR-222) and do the following. An implementation is included in Java SE 6.
Demo
package forum10520757;
import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StringReader xml = new StringReader("<person><id>QZhx_w1eEJ</id><first-name>pratap</first-name><last-name>murukutla</last-name></person>");
Person person = (Person) unmarshaller.unmarshal(xml);
System.out.println(person.id);
System.out.println(person.firstName);
System.out.println(person.lastName);
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
static class Person {
String id;
#XmlElement(name="first-name")
String firstName;
#XmlElement(name="last-name")
String lastName;
}
}
Output
QZhx_w1eEJ
pratap
murukutla
You can start with:
ByteArrayInputStream inputStream =
new ByteArrayInputStream(response.getBody().getBytes("UTF-8"));
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document doc = builder.parse(new InputSource(inputStream));
You can see an example in http://www.java2s.com/Code/Java/XML/XMLDocumentinformationbyDOM.htm
Use a SAX or DOM parser that's built into Java. Parse the String into a DOM tree, walk the tree, get your values.
http://java.sun.com/xml/tutorial_intro.html