I am getting 3 different xml input from 3 different clients:
Input 1 from Client 1: (namespace-prefix: ns2
, namespace-url: url1
)
<ns2:myroot xmlns:ns2="url1">
<ns2:mydata>
<ns2:myrate>
GBP 800.55
</ns2:myrate>
</ns2:mydata>
</ns2:myroot>
Input 2 from Client 2: (namespace-prefix: ns5
, namespace-url: url2
)
<ns5:myroot xmlns:ns5="url2">
<ns5:mydata>
<ns5:myrate>
THB 1000.70
</ns5:myrate>
</ns5:mydata>
</ns5:myroot>
Input 3 from Client 3: (namespace-prefix: <empty>
, namespace-url: url3
)
<myroot xmlns="url3">
<mydata>
<myrate>
USD 955.25
</myrate>
</mydata>
</myroot>
All 3 of them have same element names but different namespaces. So I wrote down 1 package of class files named MyRoot.java
and MyData.java
:
@XmlRootElement(name="myroot")
@XmlAccessorType(XmlAccessType.FIELD)
public class MyRoot
{ @XmlElement(name="mydata")
protected MyData mydata;
public MyData getMyData()
{ return mydata;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
public class MyData
{ @XmlElement(name="myrate")
protected String myRate;
public String getMyRate()
{ return myRate;
}
}
Here is how I tested it:
public class Test {
public static void main(String[]ar){
for(String inputFileName:new String[]{"input3.xml","input2.xml","input1.xml"}){
try{
MyRoot myRoot = (MyRoot) JAXBContext.newInstance(MyRoot.class).createUnmarshaller().unmarshal(Test.class.getClassLoader().getResourceAsStream("data/xml/jaxb/varns/"+inputFileName));
System.out.println(myRoot.getMyData());
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
My Problem is:
namespace="url3"
to @XmlRootElement
/ @XmlElement
, then I get: javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"myroot"). Expected elements are <{url3}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"myroot"). Expected elements are <{url3}myroot>
and javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"myroot"). Expected elements are <{url3}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"myroot"). Expected elements are <{url3}myroot>
namespace="url2"
to @XmlRootElement
/ @XmlElement
, then I get: javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"myroot"). Expected elements are <{url2}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"myroot"). Expected elements are <{url2}myroot>
and javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{url2}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{url2}myroot>
namespace="url1"
to @XmlRootElement
/ @XmlElement
, then I get: javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"myroot"). Expected elements are <{url1}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"myroot"). Expected elements are <{url1}myroot>
and javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{url1}myroot>
javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{url1}myroot>
My Question is:
Is there any way I can make this code suitable for varying namespaces?
Since I needed the code to work for different namespaces for each input, I made following change s in the code:
NAMESPACE
in NamespaceFilter
non-static. Demo.java
code to MyRootUtils.java
that has mehtod named getMyRoot
JaxbContext.newInstance("url1")
I found that there is no such newInstance()
which takes namespace-url
as an argument. So I changed it to: newInstance(Myroot.class)
. Test.java
to suit the new classes. MyRootUtils.java
package data.xml.jaxb.varns1;
import java.io.InputStream;
import javax.xml.bind.*;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.*;
public class MyRootUtils {
public static MyRoot getMyRoot(String prefix,String url,InputStream xml) throws Exception {
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(MyRoot.class);//(MyRoot.class);
// Create the XMLFilter
XMLFilter filter = new NamespaceFilter(prefix,url);
// Set the parent XMLReader on the XMLFilter
filter.setParent(SAXParserFactory.newInstance().newSAXParser().getXMLReader());
// Set UnmarshallerHandler as ContentHandler on XMLFilter
Unmarshaller unmarshaller = jc.createUnmarshaller();
UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
filter.setContentHandler(unmarshallerHandler);
// Parse the XML
filter.parse(new InputSource(xml));
return (MyRoot) unmarshallerHandler.getResult();
}
}
NamespaceFilter.java
package data.xml.jaxb.varns1;
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private final String NAMESPACE,PREFIX;
public NamespaceFilter(String prefix,String url) {
PREFIX=prefix;
NAMESPACE=url;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("::Into endElement(uri,localName,qName):: [uri: "+uri+"],[localName: "+localName+"],[qName: "+qName+"];");
super.endElement(NAMESPACE, localName, qName);
}
@Override
public void startElement(String uri, String localName, String qName,Attributes atts)
throws SAXException {
System.out.println("::Into startElement(uri,localName,qName,atts):: [uri: "+uri+"],[localName: "+localName+"],[qName: "+qName+"];");
super.startElement(NAMESPACE, localName, qName, atts);
}
@Override
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
System.out.println(prefix+"="+uri);
super.startPrefixMapping(PREFIX, NAMESPACE);
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
super.endPrefixMapping(PREFIX);
}
}
Test.java
package data.xml.jaxb.varns1;
import java.io.InputStream;
public class Test {
public static void main(String[]ar){
String[] files={"input3.xml","input2.xml","input1.xml"};
String[] urls ={"url3","url2","url1"};
String[] prfs ={"","ns5","ns2"};
for(int i = 0 ; i < 3 ; ++i){
try{
String prefix=prfs[i];
String url = urls[i];
InputStream xml = Test.class.getClassLoader().getResourceAsStream("data/xml/jaxb/varns1/"+files[i]);
MyRoot myRoot = MyRootUtils.getMyRoot(prefix,url, xml);
System.out.println(myRoot.getMyData().getMyRate());
}catch (Exception e) {
System.err.println(e.getCause());
}
}
}
}
However I still got this output:
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: myroot];
javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{}myroot>
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns5:myroot];
javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"ns5:myroot"). Expected elements are <{}myroot>
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns2:myroot];
javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"ns2:myroot"). Expected elements are <{}myroot>
Which meant something was missing.
Here is the full stacktrace of one of the exceptions(namespace without prefix):
javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{}myroot>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:648)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:236)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:231)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:105)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1051)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:484)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135)
at org.xml.sax.helpers.XMLFilterImpl.startElement(XMLFilterImpl.java:527)
at data.xml.jaxb.varns1.NamespaceFilter.startElement(NamespaceFilter.java:20)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:501)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.startElement(XMLDTDValidator.java:767)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1363)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$ContentDriver.scanRootElementHook(XMLDocumentScannerImpl.java:1315)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3104)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:921)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:647)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
at org.xml.sax.helpers.XMLFilterImpl.parse(XMLFilterImpl.java:333)
at data.xml.jaxb.varns1.MyRootUtils.getMyRoot(MyRootUtils.java:31)
at data.xml.jaxb.varns1.Test.main(Test.java:15)
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"url3", local:"myroot"). Expected elements are <{}myroot>
... 27 more
Here is another stacktrace (namespace with prefix):
javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"ns5:myroot"). Expected elements are <{}myroot>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:648)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:236)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:231)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:105)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1051)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:484)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135)
at org.xml.sax.helpers.XMLFilterImpl.startElement(XMLFilterImpl.java:527)
at data.xml.jaxb.varns1.NamespaceFilter.startElement(NamespaceFilter.java:20)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:501)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.startElement(XMLDTDValidator.java:767)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1363)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$ContentDriver.scanRootElementHook(XMLDocumentScannerImpl.java:1315)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3104)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:921)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:647)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
at org.xml.sax.helpers.XMLFilterImpl.parse(XMLFilterImpl.java:333)
at data.xml.jaxb.varns1.MyRootUtils.getMyRoot(MyRootUtils.java:31)
at data.xml.jaxb.varns1.Test.main(Test.java:15)
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"ns5:myroot"). Expected elements are <{}myroot>
... 27 more
Adding namespace="url1"
is of no use either, as I still got same stack of exceptions.
The output: (without namespace="url1"
)
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns5:myroot];
javax.xml.bind.UnmarshalException: unexpected element (uri:"url2", local:"ns5:myroot"). Expected elements are <{}myroot>
The output: (with namespace="url1"
)
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns2:myroot];
javax.xml.bind.UnmarshalException: unexpected element (uri:"url1", local:"ns2:myroot"). Expected elements are <{url1}myroot>
Shows that namespace resolution is not yet complete.
Finally, I made 2 more changes:
I used the .replace("old-string","new-string")
method of String
class in NamespaceFilter.java
to reduce qName
(The fully qualified element-name), like this:
super.endElement(NAMESPACE, localName, qName);
changed to:
super.endElement("", localName, qName.replace(PREFIX+":", ""));
super.startElement(NAMESPACE, localName, qName, atts);
changed to:
super.startElement("", localName, qName.replace(PREFIX+":", ""), atts);
Code for NamespaceFilter.java
:
package data.xml.jaxb.varns1;
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private final String NAMESPACE,PREFIX;
public NamespaceFilter(String prefix,String url) {
PREFIX=prefix;
NAMESPACE=url;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("::Into endElement(uri,localName,qName):: [uri: "+uri+"],[localName: "+localName+"],[qName: "+qName+"];");
super.endElement("", localName, qName.replace(PREFIX+":", ""));
}
@Override
public void startElement(String uri, String localName, String qName,Attributes atts)
throws SAXException {
System.out.println("::Into startElement(uri,localName,qName,atts):: [uri: "+uri+"],[localName: "+localName+"],[qName: "+qName+"];");
super.startElement("", localName, qName.replace(PREFIX+":", ""), atts);
}
@Override
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
System.out.println(prefix+"="+uri);
super.startPrefixMapping(PREFIX, NAMESPACE);
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
super.endPrefixMapping(PREFIX);
}
}
The output now is:
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: myroot];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: mydata];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: mydata];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: myroot];
USD 955.25
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns5:myroot];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns5:mydata];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns5:myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns5:myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns5:mydata];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns5:myroot];
THB 1000.70
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns2:myroot];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns2:mydata];
::Into startElement(uri,localName,qName,atts):: [uri: ],[localName: ],[qName: ns2:myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns2:myrate];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns2:mydata];
::Into endElement(uri,localName,qName):: [uri: ],[localName: ],[qName: ns2:myroot];
GBP 800.55
However, this raises a few concerns:
String.replace()
each time there is a startElement()
& endElement()
It makes me think if this approach for variable-namespace should be acceptable at all. If there is anything that can be done to improve this code, then I request the community to mention it in the answers/comments and help do away with this probably flawed approach.
For any XML that corresponds directly to the namespace that you have mapped to in the Java model you can marshal/unmarshal it normally
You can apply a SAX XMLFilter
when unmarshalling to that when you are processing an XML document that corresponds to the schema with namespace url2
it appears as though it corresponds to the schema with namespace url1
.
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private static final String NAMESPACE = "url1";
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(NAMESPACE, localName, qName);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
super.startElement(NAMESPACE, localName, qName, atts);
}
}
Demo Code
Here is some sample code demonstrating how to apply the XMLFilter
.
import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
public class Demo {
public static void main(String[] args) throws Exception {
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance("url1");
// 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("input.xml");
filter.parse(xml);
Object result = unmarshallerHandler.getResult();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.