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");
Related
I have an xml like below:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ns0:studentDetails>xmlns:e = "http://XXXXXXXXX/school/" category = "school">
<ns0:studentName>John</ns0:studentName>
<ns0:studentCode>3376</ns0:studentCode>
<ns0:studentCGPA>8.5</ns0:studentCGPA>
</ns0:studentDetails>
I would like to iterate over xml and replace the old values with the new values.
I'm passing file path to method from my test case
import org.junit.Test;
public class MyTest {
#Test
void testXmlModify(){
String filePath = "C:/Users/john/myxml.xml";
DOMParserModify.xmlModify(filePath);
}
}
As I'm new to domparser, I have tried sevaral approaches but not fulfill my requirement.
public class DOMParserModify{
String filePath = "C:/Users/john/myxml.xml";
File xmlFile = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
xmlModify() method is as below:
public void xmlModify(Document doc) {
NodeList student = doc.getElementsByTagName("studentDetails");
Element element = null;
for(int i=0; i<stu.getLength();i++){
element = (Element) student.item(i);
String name = element.getElementsByTagName("StudentName").item(0).getNodeValue();
if(name.equalsIgnoreCase("John")){
element.setAttribute("Smith"));
}
String code = code.getElementsByTagName("studentCOde").item(0).getNodeValue();
if(code.equalsIgnoreCase("3376")){
element.setAttribute("7244"));
}
String cgpa = cgpa.getElementsByTagName("studentCGPA").item(0).getNodeValue();
if(cgpa.equalsIgnoreCase("8.5")){
element.setAttribute("9.2"));
}
}
}
updated values should be saved in same xml file i.e., myxml.xml
my final xml should look like below with the updated vales.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ns0:studentDetails>xmlns:e = "http://XXXXXXXXX/school/" category = "school">
<ns0:studentName>Smith</ns0:studentName>
<ns0:studentCode>7244</ns0:statusCode>
<ns0:studentCGPA>9.2</ns0:statusCGPA>
</ns0:studentDetails>
Could you please correct me where I'm gone wrong.
Thanks
There is "original" XML
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<context xmlns="urn:zimbra">
<session id="555">555</session>
<change token="333"/>
</context>
</soap:Header>
<soap:Body>
<AuthResponse xmlns="urn:zimbraAccount">
<lifetime>172799999</lifetime>
<session id="555">555</session>
<skin>carbon</skin>
</AuthResponse>
</soap:Body>
</soap:Envelope>
The XML is parsed in this way
// javax.xml.parsers.*
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(pathToXml);
Then I'm trying to extract session id by XPath
// javax.xml.xpath.*;
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
// next xpath does not work with Java and online xpath tester
//XPathExpression expr = xpath.compile("/soap:Envelope/soap:Header/context/session/text()");
// this xpath works with online xpath tester but does not with in Java
XPathExpression expr = xpath.compile("/soap:Envelope/soap:Header/*[name()='context']/*[name()='session']/text()");
String sessionId = (String)expr.evaluate(doc, XPathConstants.STRING);
Tested here
http://www.xpathtester.com/xpath/678ae9388e3ae2fc8406eb8cf14f3119
When the XML is simplified to this
<Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<Header>
<context>
<session id="555">555</session>
<change token="333"/>
</context>
</Header>
<Body>
<AuthResponse xmlns="urn:zimbraAccount">
<lifetime>172799999</lifetime>
<session id="555">555</session>
<skin>carbon</skin>
</AuthResponse>
</Body>
</Envelope>
This XPath does its job
XPathExpression expr = xpath.compile("/Envelope/Header/context/session/text()");
How to extract session id from "original" XML with Java?
UPDATE: JDK 1.6
The answer is that you need to correctly use namespaces and namespace prefixes:
First, make your DocumentBuilderFactory namespace aware by calling this before you use it:
factory.setNamespaceAware(true);
Then do this to retrieve the value you want:
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
#Override
public String getNamespaceURI(String prefix) {
if (prefix.equals("soap")) {
return "http://www.w3.org/2003/05/soap-envelope";
}
if (prefix.equals("zmb")) {
return "urn:zimbra";
}
return XMLConstants.NULL_NS_URI;
}
#Override
public String getPrefix(String namespaceURI) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public Iterator getPrefixes(String namespaceURI) {
throw new UnsupportedOperationException("Not supported yet.");
}
});
XPathExpression expr =
xpath.compile("/soap:Envelope/soap:Header/zmb:context/zmb:session");
String sessionId = (String)expr.evaluate(doc, XPathConstants.STRING);
You may need to add a line to the beginning of your file to import the NamespaceContext class:
import javax.xml.namespace.NamespaceContext;
http://ideone.com/X3iX5N
You can always do it by ignoring namespace, not the ideal method but works.
"/*[local-name()='Envelope']/*[local-name()='Header']/*[local-name()='context']/*[local-name()='session']/text()"
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
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;
}
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";