users@jaxb.java.net

Problem marshaling <xs:any> element with attributes

From: Anand Navale <naanand_at_novell.com>
Date: Thu, 14 May 2009 04:23:36 -0600

Hi,

I am using Java 5 and JAXB RI 2.1.7 for my project and XJC utility coming with it for generating java code mapping to the XML schema. I m facing problems marshaling an object which has one of its fields mapping to <xs:any> type. Specifically, the problem arises whenever the XML DOM element mapping the <xs:any> element includes attributes. For the schema mentioned below:
SCHEMA:
<!-- --------------------------------------------------------------------------- -->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns="http://www.company.com/Product/Component/v1.0"
                targetNamespace="http://www.company.com/Product/Component/v1.0"
        elementFormDefault="qualified" attributeFormDefault="unqualified">
        <xs:complexType name="Element">
                <xs:sequence>
                        <xs:element name="Name" type="xs:string" minOccurs="0" />
                        <xs:element name="Description" type="xs:string" minOccurs="0" />
                        <xs:element name="Data" minOccurs="0">
                                <xs:complexType>
                                        <xs:sequence>
                                                <xs:any/>
                                        </xs:sequence>
                                </xs:complexType>
                        </xs:element>
                </xs:sequence>
                <xs:attribute name="Type" type="xs:string" />
                <xs:attribute name="Id" type="xs:string" use="required" />
        </xs:complexType>
        <xs:complexType name="ElementSet">
                <xs:sequence>
                        <xs:element name="Element" type="Element" minOccurs="0" maxOccurs="unbounded"/>
                        <xs:element name="ElementSetAny" minOccurs="0">
                                <xs:complexType>
                                        <xs:sequence>
                                                <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
                                        </xs:sequence>
                                </xs:complexType>
                        </xs:element>
                </xs:sequence>
                <xs:attribute name="Type" type="xs:string"/>
                <xs:attribute name="Version" type="xs:long" use="optional"/>
        </xs:complexType>
</xs:schema> <!-- schema ends here -->
<!-- --------------------------------------------------------------------------- -->

marshaling produces the following XML data which looks malformed:

<!-- --------------------------------------------------------------------------- -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ElementSet Version="0" Type="es1" xmlns:ns2="http://www.company.com/Product/Component/v1.0">
    <ns2:Element Id="1" Type="e_type1">
        <ns2:Name>e1</ns2:Name>
        <ns2:Data>
            <ns2:someData xmlns="http://www.company.com/Product/Component/v1.0">
                <data1 name="one" xmlns:ns4="http://www.company.com/Product/Component/v1.0" xmlns="">
                    <ns4:data2>1234</ns4:data2>
                    <ns4:data3>1234</ns4:data3>
                </data1>
            </ns2:someData>
        </Data>
    </Element>
</ElementSet>
<!-- --------------------------------------------------------------------------- -->

On unmarshaling the above generated XML I get the following exception:

DefaultValidationEventHandler: [FATAL_ERROR]: The element type "ns2:Data" must be terminated by the matching end-tag "</ns2:Data>".
     Location: line 1
javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException: The element type "ns2:Data" must be terminated by the matching end-tag "</ns2:Data>".]
        at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:510)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:215)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:190)
        at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:241)

Have referred to https://jaxb.dev.java.net/guide/Mapping_of__xs_any___.html and but could not get any useful information. Have also included the marshaling/unmarshaling code. Please let me know if any extra information needs to be supplied so that marshaling produces the right XML.

CODE:
/*********************************************************************/
        public void testJaxbProcessing() throws Exception, JAXBException {
                ElementSet es = new ElementSet();
                es.setType("es1");
                es.setVersion(Long.valueOf(0L));

                Element e = new Element();
                e.setName("e1");
                e.setType("e_type1");
                e.setId("1");
                Data data = new Data();

                                // DOM element with attributes - does not work.
                Document anyValue = getDOMfromXML(new StringReader("<someData xmlns=\"http://www.company.com/Product/Component/v1.0\"><data1 name=\"one\"><data2>1234</data2><data3>1234</data3></data1></someData>"));

                               /*
                 * DOM element without attributes - works
                 * Document anyValue = getDOMfromXML(new StringReader("<someData xmlns=\"http://www.company.com/Product/Component/v1.0\"><data1><data2>1234</data2><data3>1234</data3></data1></someData>"));
                 */
                                 
                data.setAny(anyValue.getDocumentElement());
                e.setData(data);
                es.getElement().add(e);
                JAXBElement<ElementSet> jaxbElem = new JAXBElement<ElementSet>(
                                new QName("", ElementSet.class.getSimpleName()),
                                ElementSet.class, null, es);
                
                               // MARSHALLING
                                String esString = marshal(jaxbElem, ElementSet.class.getPackage().getName(), ElementSet.class.getClassLoader());
                
                System.out.println(esString);
        
                               // UNMARSHALLING
                es = (ElementSet) unmarshal(new StringReader(esString), ElementSet.class);
                
                System.out.println("Finally element set : " + es.getType() + ", " + es.getVersion());
        }

        public String marshal(Object object,
                        String objectGraphPackage, ClassLoader classloader) throws JAXBException {
                JAXBContext context = JAXBContext.newInstance(objectGraphPackage,
                                classloader);
                Marshaller marshaller = context.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                StringWriter sw = new StringWriter();
                marshaller.marshal(object, sw);
                return sw.toString();
        }
        
        public Object unmarshal(Reader xmlReader, Class declaredType) throws JAXBException {
                JAXBContext context = JAXBContext.newInstance(declaredType.getPackage().getName(),
                                declaredType.getClassLoader());
                Unmarshaller unmarshaller = context.createUnmarshaller();
                unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
                Object object = unmarshaller.unmarshal(new StreamSource(xmlReader), declaredType);
                if(object instanceof JAXBElement) {
                        return ((JAXBElement) object).getValue();
                } else {
                        return object;
                }
        }

        private Document getDOMfromXML(Reader reader) throws Exception{

                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                InputSource is = new InputSource(reader);
                Document document = builder.parse(is);
                return document;
        }
/*********************************************************************/

Thanks in advance,
Anand Navale