Unmarshall xml using Document instead of StreamSource - java

I previously unmarshaled my documents with this Method from "javax.xml.bind.Unmarshaller" (i am using Moxy as jaxb provider):
<Object> JAXBElement<Object> javax.xml.bind.Unmarshaller.unmarshal(Source source, Class<Object> declaredType) throws JAXBException
Now i have to refactor my code to use
<?> JAXBElement<?> javax.xml.bind.Unmarshaller.unmarshal(Node node, Class<?> declaredType) throws JAXBException
The problem is that i get an unmarshal exception:
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: org.xml.sax.SAXParseExceptionpublicId: ; systemId: ; lineNumber: 0; columnNumber: 0; cvc-elt.1: Cannot find the declaration of element 'invoice:request'.]
i tried unmarshal with Document and with Document.getDocumentElement(). The data in document is the same as in InputStream. Document is created this way:
protected static Document extractDocument(InputStream sourceData) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
Document doc;
try {
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.parse(new InputSource(sourceData));
} catch (Exception e) {
throw new IllegalArgumentException("Problem on reading xml, cause: ", e);
}
return doc;
}
I need the "intermediate" Document to do the type recognition/ to get the second argument for unmarshal.
so how to use the unmarshal method with Node/Document that the outcome is the same as used with the inputstream?
Edit for rick
I am unmarshalling xml data from here xsds are in this zip and examples are here.
i wrote a simple test (jaxb provider is moxy, it was also used to generate the binding classes):
#Test
public void test() throws Exception {
Unmarshaller um;
JAXBContext jaxbContext = JAXBContext
.newInstance("....generatedClasses.invoice.general430.request");
um = jaxbContext.createUnmarshaller();
InputStream xmlIs = SingleTests.class.getResourceAsStream("/430_requests/dentist_ersred_TG_430.xml");
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(this.getClass().getResource("/xsd/" + "generalInvoiceRequest_430.xsd"));
// start
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
Document doc;
try {
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.parse(new InputSource(xmlIs));
} catch (Exception e) {
throw new Exception("Problem on recognizing invoice type of given xml, cause: ", e);
}
// end
um.setSchema(schema);
um.unmarshal(doc, ....generatedClasses.invoice.general430.request.RequestType.class);
}
This is not working with the error described above. But as soon as deleted the "start end block" and unmarshall the stream xmlIs directly (not using the Document) the code works.

Ok i asked the same Question here the answer is:
simple add
docBuilderFactory.setNamespaceAware(true);

The following code works for me with a simple test model and gives the same result in all three cases:
JAXBContext ctx = JAXBContext.newInstance(new Class[] { TestObject.class }, null);
Source source = new StreamSource("src/stack16038604/instance.xml");
JAXBElement o1 = ctx.createUnmarshaller().unmarshal(source, TestObject.class);
System.out.println(o1.getValue());
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
InputStream inputStream2 = ClassLoader.getSystemResourceAsStream("stack16038604/instance.xml");
Document node = builderFactory.newDocumentBuilder().parse(inputStream2);
JAXBElement o2 = ctx.createUnmarshaller().unmarshal(node, TestObject.class);
System.out.println(o2.getValue());
DocumentBuilderFactory builderFactory2 = DocumentBuilderFactory.newInstance();
InputStream inputStream3 = ClassLoader.getSystemResourceAsStream("stack16038604/instance.xml");
InputSource inputSource = new InputSource(inputStream3);
Document node2 = builderFactory2.newDocumentBuilder().parse(inputSource);
JAXBElement o3 = ctx.createUnmarshaller().unmarshal(node2, TestObject.class);
System.out.println(o3.getValue());
If you provided a systemId in the Source use-case, then you should use the same systemId on the InputSource you create:
inputSource.setSystemId(sameIdAsYouUsedForSource);
If you are still having problems could you post the XML that you are trying to unmarshal? Also if your JAXB objects were generated from an XML Schema that could provide useful information as well.
Hope this helps,
Rick

Related

UnmarshalException error

I'm trying to unmarshal my DOM parsed document so that I can update my XML. But I got the following namespace error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"Showing_Today"). Expected elements are <{http://xml.netbeans.org/schema/Shows}Showing_Today>
Here is my: package-info.java
#javax.xml.bind.annotation.XmlSchema
(namespace = "http://xml.netbeans.org/schema/Shows", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package Media;
Here is my XML file that I'm trying to unmarshal:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Showing_Today xmlns="http://xml.netbeans.org/schema/Shows">
<movie_collection>
<Title>Red</Title>
<Director>Robert Schwentke</Director>
<Year>2010</Year>
</movie_collection>
ShowingToday.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"movieCollection"
})
#XmlRootElement(name = "Showing_Today")
public class ShowingToday {
#XmlElement(name = "movie_collection")
protected List<MovieType> movieCollection;
And here is my unmarshaller code:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document domDoc = docBuilder.parse("Now_Showing.xml");
dbf.setNamespaceAware(true);
JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(ShowingToday.class);
Binder <Node> binder = jaxbCtx.createBinder();
Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
ShowingToday shows2 = (ShowingToday) binder.unmarshal(domDoc);
I've looked at many similar questions, but none of the solutions helped. Any suggestions on how I can fix it? Thank you
You need to call setNamespaceAware() before you create the DocumentBuilder. Setting this after you've created the parser and built the DOM will have no effect. That's very likely the reason why JAXB is unable to unmarshal the root element, as it would be missing its namespace.
Try this:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document domDoc = docBuilder.parse("Now_Showing.xml");

Cannot return an org.w3c.dom.Document by web-service method

I am trying to return an XML Document Object from a java axis2 web service. When I am trying to get the Document object on the client side, it gives me these exceptions.
org.apache.axis2.AxisFault: org.apache.axis2.AxisFault: Mapping qname not fond for the package: com.sun.org.apache.xerces.internal.dom
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:531)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:375)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at com.turnkey.DataCollectorStub.getData(DataCollectorStub.java:194)
at com.turnkey.TestClient.main(TestClient.java:28)
Can I not return the Document object from a webservice ??
This service does return the XML string though.
Below is the pseudo code for the method I am using
import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
public Document getData(args)
{
String xmlSource = "/*XML string*/";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document xmlDoc = builder.parse(new InputSource(new StringReader(xmlSource)));
return xmlDoc;
}
BTW, this method works fine on the server side, But on the client side I cannot receive the Document object
Can anybody please help me.
Simple way doesn't use Document as return value, because axis2 cannot find suitable import in schema. If you generate wsdl every time you should add import org.w3c.dom.Document to wsdl schema (it is a inconvenient solution). That's why the best way in my point of view return specific entity
public Credit[] getCreditList(){
Credit[] credits = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document xmlDoc = documentBuilder.parse(XML_REAL_PATH);
Element root = xmlDoc.getDocumentElement();
List<Credit> creditsList = new ArrayList<>();
NodeList creditNodes = root.getElementsByTagName(CREDIT);
int countCreditNodes = creditNodes.getLength();
for (int i = 0; i < countCreditNodes; i++) {
Element creditElement = (Element) creditNodes.item(i);
Credit credit = new Credit();
Element child = (Element) creditElement.getElementsByTagName(OWNER).item(0);
String owner = child.getFirstChild().getNodeValue();
credit.setOwner(owner);
//...
creditsList.add(credit);
}
credits = creditsList.toArray(new Credit[creditsList.size()]);
} catch (SAXException | IOException | ParserConfigurationException ex) {
Logger.getLogger(CreditPayService.class.getName()).log(Level.SEVERE, null, ex);
}
return credits;
}

XML with namespace Validation with XSD throws exception

I have a xml file which is a response from Webservice.It has got various namespaces involved with it. When I try to validate it with appropriate XSD its throwing "org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'SOAP-ENV:Envelope'." The namespace declaration for all the namespaces are declared in the response.
Following is my code
try {
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
SAXSource mainInputStream = new SAXSource(new InputSource(new FileInputStream(new File("FIXEDINCOME_v3_0.xsd"))));
SAXSource importInputStream1 =new SAXSource(new InputSource(new FileInputStream(new File("Rating.xsd"))));
SAXSource importInputStream2 = new SAXSource(new InputSource(new FileInputStream(new File("Datatypes.xsd"))));
Source[] sourceSchema = new SAXSource[]{mainInputStream , importInputStream1, importInputStream2};
Schema schema = schemaFactory.newSchema(sourceSchema);
xmlFact.setNamespaceAware(true);
xmlFact.setSchema(schema);
DocumentBuilder builder = xmlFact.newDocumentBuilder();
xmlDOC = builder.parse(new InputSource(new StringReader(inputXML)));
NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("ns0"))
uri = "http://namespace.worldnet.ml.com/EDS/Standards/Common/Service_v1_0/";
else if (prefix.equals("ns1"))
uri = "http://namespace.worldnet.ml.com/EDS/Product/Services/Get_Product_Data_Svc_v3_0/";
else if (prefix.equals("ns2"))
uri = "http://namespace.worldnet.ml.com/DataSOA/Product/Objects/FixedIncome/FixedIncome_v3_0/";
else if (prefix.equals("ns3")) {
uri = "http://namespace.worldnet.ml.com/DataSOA/Product/Objects/Rating/Rating_v2_0/";
} else if (prefix.equals("SOAP-ENV")) {
uri = "http://schemas.xmlsoap.org/soap-envelope/";
} else
uri = null;
return uri;
}
// Dummy implementation - not used!
public Iterator getPrefixes(String val) {
return null;
}
// Dummy implemenation - not used!
public String getPrefix(String uri) {
return null;
}
};
XPathFactory xpathFact = XPathFactory.newInstance();
xPath = xpathFact.newXPath();
xPath.setNamespaceContext(ctx);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I don't think the problem is with detecting the namespace definition for the SOAP-ENV prefix. The validator needs the XSD file that defines elements used in that namespace in order to validate the SOAP-ENV:Envelope element, so you need to tell the validator where that schema is located.
I think the solution is either to add the following to your XML reponse:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://schemas.xmlsoap.org/soap/envelope/"
xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/
http://schemas.xmlsoap.org/soap/envelope/">
Or, go download that schema off the web, save it to your local filesystem as an XSD file, and add it to your sourceSchema array. The first method should be preferred as it leads to more portable code (and XML).
Have you tried using the following URI for the SOAP-ENV?
http://schemas.xmlsoap.org/soap/envelope/
The set of schemas you are providing for validation does not include the soap schema. you can either include the soap schema in the schema collection, or, if you don't care about validating the soap wrapper, just grab the actual body content element and run your validation from there.

SAXException when parsing XML file with XSD schema

I have the following XSD file:
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://www.wvf.com/schemas'
xmlns='http://www.wvf.com/schemas'
xmlns:acmewvf='http://www.wvf.com/schemas'>
<xs:element name='loft'>
</xs:element>
</xs:schema>
and the following XML file:
<?xml version="1.0"?>
<acmewvf:loft xmlns:acmewvf="http://www.wvf.com/schemas"
xmlns="http://www.wvf.com/schemas">
</acmewvf:loft>
When I execute the following Java code:
public void parse(InputStream constraints) {
final SchemaFactory schemaFactory = new XMLSchemaFactory();
final URL resource =
ClassLoader.getSystemClassLoader().getResource(SCHEMA_PATH);
final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
Document doc = null;
factory.setSchema(schemaFactory.newSchema(resource));
final DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(constraints);
I get the following SAXException (on the last line of the code):
cvc-elt.1: Cannot find the declaration
of element 'acmewvf:loft'.
(Note that SCHEMA_PATH points to the XSD file whose contents are given above and constraints is an input stream to the XML file whose contents are also given above.)
What's going wrong here?
See Using the Validating Parser. Probably, you should try to add the following to generate a namespace-aware, validating parser:
factory.setNamespaceAware(true);
factory.setValidating(true);
try {
factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
catch (IllegalArgumentException x) {
// Happens if the parser does not support JAXP 1.2
...
}
Don't forget to define:
static final String JAXP_SCHEMA_LANGUAGE =
"http://java.sun.com/xml/jaxp/properties/schemaLanguage";
static final String W3C_XML_SCHEMA =
"http://www.w3.org/2001/XMLSchema";

convert nu.XOM.Element to org.w3c.dom.Element

Is it possible to convert nu.XOM.Element to org.w3c.dom.Element?
Am trying to construct XML using XOM APIs. But few of my legacy APIs expects org.w3c.dom.Element. So, I just want to know if I can convert.
Thank You :)
There is the nu.xom.converters.DOMConverter class, which provides a way of translating an entire XOM document into a corresponding DOM document, but you can't do it for individual elements, probably because a W3C Element can't exist without a parent Document.
XOM Document:
final nu.xom.Element root = new nu.xom.Element("root");
root.appendChild("Hello World!");
final nu.xom.Document xomDoc = new nu.xom.Document(root);
using DOMConverter:
final DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final DOMImplementation impl = builder.getDOMImplementation();
final Document w3cDoc= DOMConverter.convert(xomDoc, impl);
public static org.w3c.dom.Document xomToDom(Element elem) {
try {
elem = (Element)elem.copy();
return
DOMConverter.convert(new Document(elem),
DocumentBuilderFactory.newInstance().newDocumentBuilder().getDOMImplementation());
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
}

Categories