JAXB XJC - XPath evaluation results in empty target node? - java

I've got the following simple XSD document (foo.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:foo">
<xsd:element name="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="Height">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Short"/>
<xsd:enumeration value="Average"/>
<xsd:enumeration value="Tall"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
And I'd like to hint to the XJC JAXB compiler that the "Height" element should use a type safe enum class by using an external bindings file, like so (foo.xjb):
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3c.org/2001/XMLSchema"
jxb:version="2.0">
<jxb:bindings schemaLocation="foo.xsd">
<jxb:bindings node="//xsd:element[#name='Height']/xsd:simpleType">
<jxb:typesafeEnumClass name="Height" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
But when I run the command "xjc -b foo.xjb foo.xsd" I get the following error:
parsing a schema...
[ERROR] XPath evaluation of "//xsd:element[#name='Height']/xsd:simpleType" results in empty target node
line 6 of file:/Users/maerics/src/java/jaxb/foo.xjb
Failed to parse a schema.
The XPath expression looks fine to me so I'm guessing there is some subtle problem related to XML namespaces? I've tried a few combinations of using (or not) a default namespace, targetNamespace, etc. but always the same error. Note that xjc generates Java source for the XSD file by itself, without the external bindings file, as expected. Similarly, using embedded binding definitions in the XSD file works as expected.
Note that I am using Java version "1.6.0_26" and xjc version "JAXB 2.1.10 in JDK 6" on Mac OS 10.6.8.
Can someone explain how to achieve this goal without modifying the original XSD?

Heh, you're going to kick yourself when you see the problem:
In foo.xsd, you have this:
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
In foo.xjb, you have this:
xmlns:xsd="http://www.w3c.org/2001/XMLSchema"
Note "w3" vs. "w3c". Those two attributes need to match exactly, and then your XPath will work (otherwise the namespace referenced in your xjb is distinct from the XSD namespace referenced in your XSD.)

Related

Issue with generating sources from xsd schema

I'm getting the following error when generating sources for my project. I have extracted a few common types to a schema called CommonTypes.xsd and I get the following error:
org.xml.sax.SAXParseException: src-resolve.4.1: Error resolving component 'nonEmptyString'. It was detected that 'nonEmptyString' has no namespace, but components with no target namesp
ace are not referenceable from schema document 'file:/C:/Workspace/CommonTypes.xsd'. If 'nonEmptyString' is
intended to have a namespace, perhaps a prefix needs to be provided. If it is intended that 'nonEmptyString' has no namespace, then an 'import' without a "namespace" attribute should
be added to 'file:/C:/Workspace/lps-performance-calculation-service/pcs-data/src/main/resources/xsd/calc/lps/CommonTypes.xsd'.
The following simple type is defined in my CommonTypes.xsd schema as below:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:unit="http://www.mywebsite.com/unit"
xmlns:types="http://www.mywebsite.com/types"
elementFormDefault="qualified" attributeFormDefault="unqualified"
targetNamespace="http://www.mywebsite.com//types">
<!-- import types -->
<xsd:import namespace="http://www.mywebsite.com/unit"/>
<!-- other common types -->
<xsd:simpleType name="nonEmptyString">
<xsd:restriction base="xsd:string">
<xsd:minLength value="1"/>
<xsd:pattern value=".*[^\s].*"/>
</xsd:restriction>
</xsd:simpleType>
And line 241 which causes the error is below:
<xsd:complexType name="Message">
<xsd:simpleContent>
<xsd:extension base="nonEmptyString">
<xsd:attribute type="xsd:string" name="code" use="required"/>
<xsd:attribute name="category" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:token">
<xsd:enumeration value="Error"/>
<xsd:enumeration value="Info"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute type="xsd:string" name="component" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
Do you have any idea what may cause the error? I've tried searching through StackOverflow and experimenting with the targetNamespace and xmlns, but with no success.
You are trying to refer to a simple type which has
name 'nonEmptyString'
namespace ""
But the simple type 'nonEmptyString' is defined in this XSD, which has targetNamespace="http://www.mywebsite.com//types". So you should be referring to a simple type which has
name 'nonEmptyString'
namespace "http://www.mywebsite.com//types"
You simply need to change this:
<xsd:extension base="nonEmptyString">
to this:
<xsd:extension base="types:nonEmptyString">
You need to import your nonEmptyString in the corresponding namespace and make this namespace referenceable via the prefix.
To do this, add xmlns:types="http://www.mywebsite.com/types" to xsd:schema of the importing schema.
Also provide the namespace in xsd:import of the importing schema. Should be something like:
<xsd:import
namespace="http://www.mywebsite.com/types"
schemaLocation="calc/lps/CommonTypes.xsd"/>
Then you should be able to reference your nonEmptyString type as types:nonEmptyString.

FpML Custom binding jaxb

I'm required to use FpML in my project and struggling with generating Java class by JAXB:
[ERROR] Element "{http://www.fpml.org/FpML-5/confirmation}tradeId" shows up in more than one properties.
line 1142 of file:/D:/FpML/schema/fpml/5-5/confirmation/fpml-doc-5-5.xsd
fpml-doc-5.5.xsd is imported into the master schema.
I tried to use inline custom binding (I gave up using an external file) as follows:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns="http://www.fpml.org/FpML-5/confirmation" xmlns:fpml-annotation="http://www.fpml.org/annotation" targetNamespace="http://www.fpml.org/FpML-5/confirmation" ecore:documentRoot="FpML" ecore:nsPrefix="conf" ecore:package="org.fpml.confirmation" version="$Revision: 10163 $" elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:version="1.0">
....
<xsd:element name="issuer" type="IssuerId"></xsd:element>
<xsd:element name="tradeId" type="TradeId">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="tradeIdentifierId"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
The same error still occurs.
Directly editing the schema to rename tradeId would solve the issue but I can't do that. I still can define my own inline binding though.
Can you please shed some light?
Use JAXB version 2. I'm using jaxb-xjc 2.1.13 without issues for FPML 5.5 confirmation.

marshall with xjc created nested classes

<ProductInformation Context="GL">
<Assets>
<Asset ID="assetID" UserTypeID="ID">
<Name>name</Name>
<Reference ClassificationID="id"/>
<Values>
<Value AttributeID="ID">Value1</Value>
<Value AttributeID="ID">Value2</Value>
<MultiValue AttributeID="attributeID">
<Value>value3a</Value>
<Value>value3b</Value>
</MultiValue>
</Values>
</Asset>
</Assets>
<Products>....</Products>
</ProductInformation>
I used this xml->xsd and xjc to create classes from it.
Now I want to create my ProductInformation object,and marshall it.
My problem is xjc create 3 classes and a objectfactory, and some nested classes inside ProductInformation. When I look at the avaliable methods I mostly see getters instead of setters.
"Asset" class has no such methods like;
asset.setValues(List<Value> values)
Also I ended up writing funny code like this;
ProductInformation.Assets.Asset.Values.MultiValue multivalue=new ProductInformation.Assets.Asset.Values.MultiValue();
Is this normal with Jaxb?
The answer given by Ian Roberts is the correct one. I am giving this one to provide some additional information for those people interested in not having inner classes.
XML Schema (schema.xsd)
If JAXB classes are generated from the following XML schema, both the resulting Customer and Employee classes will contain a static nested class called Address (because each contains their own definition of an address). This is in fact why static nested classes are used to avoid name conflict problems.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://www.example.org/company"
xmlns="http://www.example.org/company"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element name="customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="street" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="employee">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="road" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
JAXB Binding File (binding.xml)
A bindings file is used to customize the schema to Java generation. You can specify that everything should be a top level class with localScoping="top-level". When you do this you must make sure to resolve any potential name conflicts.
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings localScoping="toplevel"/>
<jaxb:bindings schemaLocation="company.xsd">
<jaxb:bindings node="//xsd:element[#name='employee']/xsd:complexType/xsd:sequence/xsd:element[#name='address']/xsd:complexType">
<jaxb:class name="EmployeeAddress"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
XJC Call
Below is an example of specifying a bindings file when using the XJC command to generate Java classes from an XML schema.
xjc -b binding.xml schema.xsd
For More Information
http://blog.bdoughan.com/2011/07/jaxb-xjc-and-nested-classes.html
The way JAXB normally handles multi valued properties is to provide just a getter and no setter for the List<Whatever>, which returns a mutable list - you're supposed to call the getter to retrieve an initially-empty list and then create the member objects for this list using new in the normal way and add them directly to the list. You can new a static nested class in exactly the same way as a top-level one.
Single-valued properties (not lists) should have been generated with both getter and setter.
This is actually just a comment to Blaise Doughan's answer but I want to post the xml.
If you work with a more complex xsd and the path in the node attribute is getting too long, you can:
<jaxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jaxb:globalBindings localScoping="toplevel"/>
<jaxb:bindings schemaLocation="company.xsd">
<jaxb:bindings node="//xsd:element[#name='employee']">
....
<jaxb:bindings node=".//xsd:element[#name='address']/xsd:complexType">
<jaxb:class name="EmployeeAddress"/>
</jaxb:bindings>
....
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>

Error: Failed to parse a schema by xjc in case of xs:choice

I'm want to generate java classes from a schema using jaxb, but I am getting a parsing error from xjc. I have 2 elements wrapped in a choice then one of the element is again repeated just after choice:
<xs:element name="A">
<xs:complexType>
<xs:choice>
<xs:sequence maxOccurs="unbounded">
<xs:element ref="X"/>
<xs:element ref="Y"/>
</xs:sequence>
<xs:element ref="Y"/>
</xs:choice>
</xs:complexType>
</xs:element>
jaxb is throwing:
[ERROR] Element "{*something*}Y" shows up in more than one properties.
line *something* of file:/*something*.xsd
PS: my jaxb version is 2.1.13
Take a look at this post on SO. The solution is to provide a custom binding file that maps your Y outside the choice to use another property name.
I would probably also map the recurring sequence to a class with two properties (X and Y), but that's something else.
I've also tried a test schema (derived from yours, just added dummy complex elements for X and Y) with version 7.1 of the free NetBeans IDE and it worked out without any need for a custom binding file. The JAXB version that I've used is 2.2.4
I've also tried to make it work as Petru described. Rahul hasn't posted his solution so here my bindings file.
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jaxb:extensionBindingPrefixes="xjc"
version="2.1">
<jaxb:bindings schemaLocation="test.xsd" node="//xs:element[#name='A']/xs:complexType/xs:choice[1]">
<jaxb:property name="OutsideY"/>
</jaxb:bindings>
</jaxb:bindings>
XJC output:
$xjc -version
xjc version "JAXB 2.1.10 in JDK 6"
JavaTM Architecture for XML Binding(JAXB) Reference Implementation, (build JAXB 2.1.10 in JDK 6)
$xjc -p com.example.test -d src -extension -b bindings.xml test.xsd
parsing a schema...
compiling a schema...
com\example\test\A.java
com\example\test\ObjectFactory.java
Maybe someone will read this:
org.jvnet.jaxb2_commons . jaxb2-basics is not working on references !
I have really tried many ways to make this plugin work, and you just can't. (It is also mentioned on github page)
#Stanislav Mamontov helped me a lot.
If somebody is curious, this also works for groups:
XSD:
<xsd:group name="OpticalID">
<xsd:sequence>
<xsd:choice>
<xsd:sequence>
<xsd:group ref="MPCID"/>
<xsd:element ref="trkSub" minOccurs="0"/>
</xsd:sequence>
<xsd:sequence>
<xsd:element ref="trkSub"/>
</xsd:sequence>
</xsd:choice>
</xsd:sequence>
BINDING:
<jaxb:bindings node="xsd:group[#name='OpticalID']//xsd:sequence[1]/xsd:choice[1]/xsd:sequence[1]/xsd:element[#ref='trkSub']">
<jaxb:property name="trkSubOrNull"/>
</jaxb:bindings>

JAXB Generation nillable=true

Using JAXB 2.2.4 I am generating Java code with the following binding file:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<globalBindings generateElementProperty="false">
</globalBindings>
Unfortunately, the generated code has a nillable = true annotation. See the following example:
#XmlElement(name = "ArtID", nillable = true)
protected STEBeitrag artID;
This is the definition of STEBeitrag:
<xsd:complexType name="CT_Beitrag">
<xsd:complexContent>
<xsd:extension base="allgemein:CT_Objekt">
<xsd:sequence>
<xsd:element name="ArtID" type="daten:STE_Beitrag" minOccurs="0" maxOccurs="1" nillable="true"/></xsd:element>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="STE_Beitrag" abstract="true">
<xsd:simpleContent>
<xsd:extension base="xsd:string"/>
</xsd:simpleContent>
</xsd:complexType>
If I do not set the ArtID in the generated CT_Beitrag object then the unmarshaller produces an output like
<ns:ArtID xsi:nil="true"/>
The element ArtID has an abstract type and therefore this XML output is invalid.
How can I generate code with JAXB that omits the nillable=true in the XmlElement annotation?
By the way, the schema canĀ“t be changed.
I have no solution, but this problem is addressed in bug
http://java.net/jira/browse/JAXB-890
I hope this problem wil be solved.
I don't how to do what you're asking and I'd be surprised if what you're asking is worth the effort.
There are 2 options that jump to my mind:
Change the schema (I know you said you can't but perhaps you can take a local copy of the schema if you can't change it due to it being hosted on a server outside of your control)
Change the generated code... simply change nillable=true to nillable=false

Categories