Question

I have a business requirement to generate XML from classes (defined in a Schema) in as lightweight a form as possible. To achieve this I have removed all namespace information from the xml.

Sample schema:

<xs:schema xmlns="http://aschema/" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           targetNamespace="http://aschema/" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">

  <xs:element name="Test" type="TestType"/>
  <xs:complexType name="TestType">
    <xs:sequence>
      <xs:element name="test" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Generates a Test class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TestType", propOrder = {
    "test"
})
@XmlRootElement(name = "Test")
public class Test {

    @XmlElement(required = true)
    protected String test;

    /**
     * Gets the value of the test property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getTest() {
        return test;
    }

    /**
     * Sets the value of the test property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setTest(String value) {
        this.test = value;
    }

}

Marshals to (I can explain how if you wish but I would think that would just clutter the question - happy to add if requested):

<Test><test>Hello World!</test></Test>

Now I want to unmarshal it. I get (not really surprisingly):

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"Test"). Expected elements are <{http://aschema/}Test>

Is there some way I can define to my unmarshal process what to use when it comes across this problem?

I cannot change the schema - it is an industry standard.

I cannot change the Test object - it is generated from the schema.

All references to this error I can find seem to either point at a change in the java class or a change to the schema - I cannot do either of these things.

Note that my Test class is an attempt to create a Minimal, Complete, Tested and Readable example. The real objects I want to unmarshall are much more complex.

Was it helpful?

Solution

As usual - once I posted the problem a solution appeared - as if by Magic. That's StackOverflow for you.

From JAXB unmarshal with declared type does not populate the resulting object with data

public class NamespaceFilter extends XMLFilterImpl {

  private static final String NAMESPACE = "http://aschema/";

  @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);
  }

}

...

  // 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 = jaxbContext.createUnmarshaller();
  UnmarshallerHandler unmarshallerHandler = unmarshaller.getUnmarshallerHandler();
  filter.setContentHandler(unmarshallerHandler);

  // Parse the XML
  filter.parse(new InputSource(r));
  //Object result = unmarshallerHandler.getResult();  
  T t = (T) unmarshallerHandler.getResult();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top