Mixed content in JAXB generated files - java

Consider the following type definition in my XSD:
<xs:complexType name="ED" mixed="true">
<xs:complexContent>
<xs:extension base="BIN">
<!-- I cut some data here -->
</xs:extension>
</xs:complexContent>
</xs:complexType>
I found that JAXB has a hard time generating code for mixed elements.
I tried using <jaxb:globalBindings generateMixedExtensions="true"/>, but that isn't supported very well and generates awkward List<Serializable> code.
So I thought I could modify some element through my custom binding:
<bindings
xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0">
<bindings schemaLocation="../../processable/coreschemas/datatypes-base.xsd">
<bindings node="//xs:complexType[#mixed='true']" multiple="true">
<property>
<javaType><!-- What do I do here? --></javaType>
</property>
</bindings>
</bindings>
</bindings>
Basically, I want all elements which specify mixed=true to have a custom value or content field (String) which holds the CDATA between the tags. For instance for my ED type it could be like this in XML, the title element uses ED as its type:
<title>Hello, I'm a title!</title> should yield Hello, I'm a title! as its content.
How do I do this?
For those of you interested: I'm trying to generate code for the HL7v3 CDA specifications.

Related

jaxb idref string adapter

I'm using a standard xml schema, called isosts, I need to convert schema to java class using jaxb. In this xml schema, a lot of elements have attribute rid as type xs:IDREFS <xs:attribute name="rid" type="xs:IDREFS">. Jaxb converts xs:IDREFS to be list of Objects.
For my need, I want jaxb to make type xs:IDREFS to be just java string type in all the generated java class. And during marshall/unmarshall time, the value of attribute rid should all be handled as string. Since this is a standard schema, I have to customize jaxb. I'm not sure if this can be done in jaxb binding or adapter and how to do it. Can anyone help me?
This binding file (let's call it "binding.xjb) forces the type to String:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xsi:schemaLocation=" http://java.sun.com/xml/ns/jaxb
http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<bindings schemaLocation="SomeSchemaName.xsd" node="/xs:schema">
<bindings node="//xs:attribute[#name='rid']">
<property>
<baseType>
<javaType name="java.lang.String"></javaType>
</baseType>
</property>
</bindings>
</bindings>
</bindings>
Compile the schema using
xjc -b binding.xjb SomeSchemaName.xsd

Provide schema for xsd:any element while importing WSDL using wsimport

I have a WSDL that uses an xsd:any element in a return type for one of the methods, like this:
<xs:element name="Method_XMLResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Method_XMLResult">
<xs:complexType mixed="true">
<xs:sequence>
<xs:any/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
When I run the WSDL through the wsimport tool, I get a generated class that has this xs:any field mapped as a list of objects:
public static class MethodXMLResult {
#XmlMixed
#XmlAnyElement(lax = true)
protected List<Object> content;
}
When invoking the service using the generated code, I get instances of org.w3c.dom.Node in the content list (com.sun.org.apache.xerces.internal.dom.ElementNSImpl to be precise) that I would need to parse myself. I was, however, provided with a separate, external schema document for the objects actually returned - and I'm trying to somehow feed it to wsimport so it generates the classes for them as well.
I'm trying to accomplish that through JAX-WS / JAXB customization file like this:
<jaxws:bindings xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" xmlns:a="http://www.w3.org/2001/XMLSchema"
wsdlLocation="wsdlLocation.wsdl">
<jaxws:bindings node="wsdl:definitions">
<jaxws:bindings node="wsdl:types" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxws:bindings node="//s:schema[#targetNamespace='wsNamespace']">
<jaxb:bindings node="//s:element[#name='Method_XMLResponse']//s:any">
...
</jaxb:bindings>
</jaxws:bindings>
</jaxws:bindings>
</jaxws:bindings>
</jaxws:bindings>
Looks like wsimport picks the right location to customize (gave me numerous error meesages with properly designated line number in the WSDL), but I can't figure out how to fill the <jaxb:bindings> element to make wsimport generate classes from the external schema. Is it even possible? Any help would be much appreciated.
I see you are use mixed type with xs:any in your XSD. I think it usefull custimization for a mixed type following JAXB adjust:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateMixedExtensions="true"/>
</jaxb:bindings>
You can add external JAXB binding files to wsimport whith -b parameter.
I think you can adjust xs:any with following ways:
Skip shema:
<xs:any processContents="skip" maxOccurs="unbounded" minOccurs="0" />
Skip binding:
#XmlAnyElement
public List<Element> getAny();
Strict schema:
<xs:any maxOccurs="unbounded" minOccurs="0" />
Strict binding:
#XmlAnyElement(lax=true)
public List<Object> getAny();
and:
with processContents=lax means any XML elements can be
placed here, but if their element names match those defined in the
schema, they have to be valid. XJC actually handles this exactly like
processContents='strict', since the strict binding allows unknown
elements anyway.
You can read more about in this link.
May be help this answer to accomplish your JAX-WS / JAXB customization file.

JAXB converting XSD to Java classes

When I run the following command:
xjc -b xmlSchema.xjb -d src -p com.q1labs.qa.xmlgenerator.model.generatedxmlclasses xmlSchema.xsd
It creates Java classes however I've found that my root class does not have the correct name and does not have #XmlRootElement which declares it as a root element which means when I use the classes to generate XML it is not formed properly.
XSD Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified"
elementFormDefault="qualified" targetNamespace="http://ibm.org/seleniumframework"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Test" type="sel:TestType" xmlns:sel="http://ibm.org/seleniumframework"/>
<xs:complexType name="TestType">
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element type="sel:Option1" name="Option1" xmlns:sel="http://ibm.org/seleniumframework"/>
<xs:element type="sel:Option2" name="Option2" xmlns:sel="http://ibm.org/seleniumframework"/>
<xs:element type="sel:Option3" name="Option3" xmlns:sel="http://ibm.org/seleniumframework"/>
</xs:choice>
</xs:complexType>
This is the output I am getting:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<testType xmlns="http://ibm.org/seleniumframework"/>
Generated classes correspond to complex types. Anonymous complex types that are declared as part of global elements will get an #XmlRootElement annotation. Others will have a #XmlElementDecl annotation generated on the ObjectFactory class. This is because there may be more than one global element that corresponds to the same complex type.
For More Information
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

JAXB Unmarshall error

I'm using JAXB on my project, but from time to time, I face some problems that I can't solve. I have setup my environment like this:
Armor Class
package com.fortresswars.entity.component;
#XmlType(name = "armor", namespace = "http://fortresswars.com")
public class ArmorComponent extends AbstractComponent
package-info.java
#XmlSchema(xmlns = #XmlNs(namespaceURI = "http://fortresswars.com", prefix = "fw"), elementFormDefault = XmlNsForm.UNQUALIFIED, namespace = "http://fortresswars.com")
package com.fortresswars.entity.component;
The generated schema header is almost correct:
<xs:schema elementFormDefault="unqualified" version="1.0" targetNamespace="http://fortresswars.com" xmlns:fw="http://fortresswars.com" xmlns:tns="http://fortresswars.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
The only thing I didn't like is that TNS prefix that JAXB puts there and I can't remove. I'm using an ant task (com.sun.tools.jxc.SchemaGenTask), and I remember reading somewhere that this was the problem.
The rest of the generated scheme follows below. I'll show only the relevant part about armor:
<xs:complexType name="armor">
<xs:complexContent>
<xs:extension base="tns:abstractComponent">
<xs:sequence>
<xs:element name="value" type="xs:short" minOccurs="0"/>
<xs:element name="type" type="tns:armor-type" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
And the element that is using the armor component:
<xs:complexType name="character">
<xs:complexContent>
<xs:extension base="tns:thing">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="armor" type="tns:armor"/>
<xs:element name="model" type="tns:model"/>
<xs:element name="status" type="tns:status"/>
<xs:element name="costs" type="tns:costs"/>
</xs:choice>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
To test this, I created a XML Document (see the TNS prefix, I need to put it, or the fw prefix, along with the xmlns:fw also).
<?xml version="1.0" encoding="UTF-8"?><tns:character xmlns:tns="http://fortresswars.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<armor>
<value>5</value>
<type>NORMAL</type>
</armor>
</tns:character>
But when I'm unmarshalling this document, here's the error I get:
Exception: unexpected element (uri:"", local:"armor"). Expected elements are <{http://fortresswars.com}armor>,<{http://fortresswars.com}attacks>,<{http://fortresswars.com}costs>,<{http://fortresswars.com}model>,<{http://fortresswars.com}abilities>,<{http://fortresswars.com}status>,<{http://fortresswars.com}movement>
I have setup elementFormDefault to UNQUALIFIED, and even though this doesn't work. Why I'm getting this exception? And can I remove TNS prefix from the generated schema?
when you define a namespace prefix for elements of http://fortresswars.com you need to prefix all elements with it, not only character. So this should work
<?xml version="1.0" encoding="UTF-8"?>
<tns:character
xmlns:tns="http://fortresswars.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<tns:armor>
<tns:value>5</tns:value>
<tns:type>NORMAL</tns:type>
</tns:armor>
</tns:character>
The tns prefix used in the schema is unrelated to what you use as prefix for XML text that you unmarshal. You may choose any other in xmlns:whatyoulike="http://fortresswars.com". The key that connects the elements in the XML document to the definitions in the schema file is the namespace URI, in your case "http://fortresswars.com". If you define your namespace as default namespace, you can omit the prefix on every element:
<?xml version="1.0" encoding="UTF-8"?>
<character
xmlns="http://fortresswars.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<armor>
<value>5</value>
<type>NORMAL</type>
</armor>
</character>
The namespace prefix in the XSD file helps to avoid name clashes if you wan't to use the schema file together with other schema files that define types or elements with the same name. It does not force you to use it in the xml files you want to unmarshal.
On the other hand, when you marhshal objects to XML, the file package-info.java defines what prefix JAXB uses, but this only works in recent versions of JAXB and it's not always easy to assure that the correct version is in use when your code runs. But you may use a NamespacePrefixMapper to control that.

How to generate Java code from an XSD that includes MSFT Serialization: GUID datatypes?

I have used the Jaxme 2 libraries before to generate Java code from .XSD files without a problem. I'm currently encountering a problem generating Java from an XSD file that contains a http://schemas.microsoft.com/2003/10/Serialization/ namespace.
Some sample code from my .XSD is:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/MyMessagingTypes"
xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xs:complexType name="MyMessage">
<xs:sequence>
...
<xs:element minOccurs="0" name="MyPlanID" type="ser:guid" />
...
</xs:sequence>
</xs:complexType>
<xs:element name="MyMessage" nillable="true" type="tns:MyMessage" />
</xs:schema>
The Error I'm getting is:
Invalid element: The type {http://schemas.microsoft.com/2003/10/Serialization/}guid is not defined.
Any ideas what the problem is or how I can generate Java code from this xsd?
I don't know where the schema for http://schemas.microsoft.com/2003/10/Serialization/ is located, but you would have to find it, and make sure that Java sees both schemas. Alternatively, you could edit the XSD to include your own GUID type instead.

Categories