views:

2336

answers:

2

I'm trying to use JAXB to unmarshal an xml file into objects but have come across a few difficulties. The actual project has a few thousand lines in the xml file so i've reproduced the error on a smaller scale as follows:

The XML file:

The XSD file for producing JAXB classes

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
 <xsd:element name="catalogue" type="catalogueType"/>

 <xsd:complexType name="catalogueType">
  <xsd:sequence>
   <xsd:element ref="journal"  minOccurs="0" maxOccurs="unbounded"/>
  </xsd:sequence>
  <xsd:attribute name="title" type="xsd:string"/>
  <xsd:attribute name="publisher" type="xsd:string"/>
 </xsd:complexType>
</xsd:schema>

Code snippet 1:

final JAXBContext context = JAXBContext.newInstance(CatalogueType.class);
um = context.createUnmarshaller();
CatalogueType ct = (CatalogueType)um.unmarshal(new File("file output address"));

Which throws the error:

javax.xml.bind.UnmarshalException: unexpected element (uri:"x-schema:TamsDataSchema.xml", local:"catalogue"). Expected elements are <{}catalogue>
 at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642)
 at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
 at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
 at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:116)
 at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1049)
 at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:478)
 at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459)
 at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148)
 at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
 at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
 at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
 at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
 at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
 at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
 at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
 at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
 at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    ...etc

So the namespace in the XML document is causing issues, unfortunately if it's removed it works fine, but as the file is supplied by the client we're stuck with it. I've attempted numerous ways of specifying it in the XSD but none of the permutations seem to work.

I also attempted to unmarshal ignoring namespace using the following code:

Unmarshaller um = context.createUnmarshaller();
final SAXParserFactory sax = SAXParserFactory.newInstance();
sax.setNamespaceAware(false);
final XMLReader reader = sax.newSAXParser().getXMLReader();
final Source er = new SAXSource(reader, new InputSource(new FileReader("file location")));
CatalogueType ct = (CatalogueType)um.unmarshal(er);
System.out.println(ct.getPublisher());
System.out.println(ct.getTitle());

which works fine but fails to unmarshal element attributes and prints

null
null

Due to reasons beyond our control we're limited to using Java 1.5 and we're using JAXB 2.0 which is unfortunate because the second code block works as desired using Java 1.6.

any suggestions would be greatly appreciated, the alternative is cutting the namespace declaration out of the file before parsing it which seems inelegant.

A: 

The thing about JAXB is, it actually implements XML and XML schema correctly. That sounds like a good thing, but as you're discovering, JAXB can often be a bit ... too literal.

So, it looks like to me that you've got an XSD that says "expect a catalogue here", and then you've got XML that says "here's a {x-schema:TamsDataSchema.xml}catalogue", and unsurprisingly JAXB gets overly anal and says "that ain't cool." There is no way to workaround this that I can see; either you have to pre-parse the XML to remove the namespace, or you need to adjust your schema to allow it.

Either solution is, as you said, inelegant, but when you're trying to fit a square peg in to a round hole sometimes you need to be a bit inelegant (and you're basically saying "fit this square/namespaced peg in to a round/non-namespaced hole", so ...)

machineghost
P.S. That setNamespaceAware stuff *might* get you somewhere if you keep playing with it, but personally I have never had any luck with being able to ignore namespaces that way; not sure if I'm misunderstanding how it's supposed to work or what ... ***shrug***.
machineghost
thanks for the advice, looks like I'll just have to bite the bullet.
A: 

There is a workaround for this issue explained in this post: JAXB: How to ignore namespace during unmarshalling XML document?. It explains how to dynamically add/remove xmlns entries from XML using a SAX Filter. Handles marshalling and unmarshalling alike.

Kristofer