The JAXB Reference Implementation (JAXB RI) ships with experimental RELAX NG support, which allows users to generate Java source code from a RELAX NG schema. This document explains how to use this extension of the JAXB RI.
To compile abc.rng
, a RELAX NG schema, run the XJC
binding compiler as follows, just as if you were compiling an
XML Schema:
$ xjc.sh -relaxng abc.rng
This will compile the abc.rng
schema and put the
generated files into the current directory. All the other
xjc command-line options can be applied, no matter
regardless of the schema language you are using.
Similarly, the XJC
ant task supports
RELAX NG just like it supports XML Schema.
No matter what schema language you use, the generated code will be the same. You'll use the same JAXB API to access the generated code.
JAXB customization declarations are tailored for W3C XML Schema and, as a result, some of them don't fit well with RELAX NG. In addition, we didn't have enough resource to support all the customization in this release. Therefore, although the customization syntax for RELAX NG is similar to that for W3C XML Schema, there are some differences.
This section describes the supported customization in RELAX NG. All the examples are written with inline annotation for terseness, but the external customization is also supported.
Only package name is supported in <schemaBindings>. That is, the following shows the only legal <schemaBindings> customization.
<schemaBindings> <package name="com.acme.foo" /> </schemaBindings>
However, in RELAX NG, this customization can be applied anywhere. (In W3C XML Schema, this can be only applied to the <xs:schema> element.) This customization takes effect only on the descendants of the node to which this customization is attached.
The following example shows how to put everything into one package.
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<jaxb:schemaBindings>
<jaxb:package name="com.acme.foo"/>
</jaxb:schemaBindings>
... all the other RELAX NG declarations ...
</grammar>
The following example shows how to divide the generated code into two packages by using the RELAX NG <div> tag:
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0"> <div> <jaxb:schemaBindings> <jaxb:package name="com.acme.foo"/> </jaxb:schemaBindings> ... RELAX NG declarations ... </div> <div> <jaxb:schemaBindings> <jaxb:package name="com.acme.bar"/> </jaxb:schemaBindings> ... RELAX NG declarations ... </div> </grammar>
If you have two schemas, foo.rng
and
bar.rng
, one of which includes the other, you can
put them into two separate packages just by writing a
<schemaBindings> element for each schema file.
Only the optional name attribute is supported. Therefore the following two are the only legal forms of the <class> customization in RELAX NG.
<class name="JavaClassName" /> <class />
However, in RELAX NG, this customization can be applied to any RELAX NG pattern or <define>. (W3C XML Schema limits where this customization can be applied.) Applying this customization to a RELAX NG pattern will map that pattern into a class. If the name attribute is unspecified, the compiler will derive one.
The following example shows how a name of a class can be
changed from its default to PersonRecord
by using
a customization.
<element name="Person">
<jaxb:class name="PersonRecord"/>
<element name="first"><text/></element>
<element name="last"><text/></element>
</element>
This customization can be used to map something to a class when its not mapped to a class by default. The following example illustrates how to map a part of a group to its own class.
<element name="Address">
<group>
<jaxb:class name="Name"/>
<element name="first"><text/></element>
<element name="last"><text/></element>
</group>
<element name="street"><text/></element>
<element name="city"><text/></element>
<element name="zip"><text/></element>
</element>
This customization can be also attached to a <define> block to map a pattern block to a class.
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<start>
<element name="root">
<ref name="sub"/>
</element>
</start>
<define name="sub">
<jaxb:class name="TSub"/>
... RELAX NG pattern ...
</define>
</grammar>
Only the optional name attribute is supported. Therefore, the following two are the only legal <property> customizations allowed by RELAX NG.
<property name="PropertyName" /> <property />
However, in RELAX NG, this customization can be applied to any
RELAX NG pattern or <define>. (W3C XML Schema
limits where this customization can be applied.)
Applying this customization to a RELAX NG pattern will map that
pattern into a property from which objects from the descendants
are assigned. If the name attribute is unspecified, the
compiler will derive one. Note that you probably want to
capitalize the first letter or you get method names like
getproperty
instead of getProperty
.
The following simple example shows how a name of a property can be changed from its default by using a customization.
<element name="Person">
<element name="first"><text/></element>
<element name="last">
<jaxb:property name="FamilyName"/>
<text/>
</element>
</element>
This customization can be used to mimic the "general content list" behavior of JAXB W3C XML Schema binding. Consider the following example:
<element name="Person"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<group>
<jaxb:property name="Data"/>
<element name="first"><text/></element>
<element name="last"><text/></element>
</group>
</element>
Without a customization, two properties "First" and "Last" will be produced. But having a customization at the root of those two properties forces those two elements to be coerced into one list property, "Data".
This is useful when you want to access the content model as a simple list when the content model is too complicated. The following example shows how to map a complicated content model into just one list property.
<element name="Root"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<group>
<jaxb:property name="Content"/>
<choice>
<element name="A"><text/></element>
<element name="B"><text/></element>
</choice>
<zeroOrMore>
<element name="C"><text/></element>
</zeroOrMore>
<element name="D"><text/></element>
</group>
</element>
In RELAX NG, this customization can be applied to any RELAX NG pattern or <define>, where the pattern doesn't contain neither <attribute> nor <element>. Applying this customization to a RELAX NG pattern will map that pattern to a Java object by using the specified conversion method.
The following example describes the simple use of this customization. This customization states that the body of the Root element shall be mapped to String
(whereas the default is java.util.BigDecimal
)
<element name="Root"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatype"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<data type="decimal">
<jaxb:javaType name="java.lang.String"
parseMethod="new" printMethod="toString" />
</data>
</element>
The parseMethod
and printMethod
attributes are optional, and their default values are new
and toString
respectively (thus the above example could be simply written as <jaxb:javaType name="java.lang.String" />
). Those methods are used for the actual conversion. You can also specify the optional hasNsContext
attribute. See the JAXB specification for details of those features.
The javaType customization is useful when you want to control the process of conversion between a string in XML and its Java representation. The following example shows how you could do this to map a list of enumeration to a bit mask.
<define name="accessRightEnum"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatype"
xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0">
<!-- you could have any combination of RWX but no duplication is allowed -->
<list>
<jaxb:javaType name="int"
parseMethod="AccessRightEnum.parse" printMethod="AccessRightEnum.print" />
<zeroOrMore>
<choice>
<value>read</value>
<value>write</value>
<value>execute</value>
</choice>
</zeroOrMore>
</list>
</define>
This customization is applied to a <list> pattern, so the parse method receives the entire string that matches to the whole list. The AccessRightEnum
class would look like:
class AccessRightEnum { public static final int READ = 1; public static final int WRITE = 2; public static final int EXECUTE = 4; public static int parse( String s ) { return (contains(s,"READ")?READ:0) +(contains(s,"WRITE")?WRITE:0) +(contains(s,"EXECUTE")?EXECUTE:0); } private static boolean contains( String s, String t ) { return s.indexOf(t)!=-1; } public static String print( int x ) { return ((x&READ!=0)?"READ ":"") +((x&WRITE!=0)?"WRITE ":"") +((x&EXECUTE!=0)?"EXECUTE ":""); } }
This section describes other customizations designed specifically for RELAX NG.
By itself, RELAX NG has no notion of inheritance. <xjc:super> can be used to introduce the inheritance relationship between two generated interfaces. Technically this customization can be also applied to any RELAX NG pattern, but it is usually applied to a <ref /> pattern where a child interface is referencing its base interface.
The following example mimics the complex type derivation of
BarType
from FooType
of W3C XML
Schema:
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="1.0"> <start> <element name="Root"> <ref name="BarType"/> </element> </start> <define name="BarType"> <ref name="FooType"> <xjc:super/> </ref> <attribute name="abc"/> <optional> <attribute name="def"/> </optional> </start> <define name="FooType"> <element name="fooContent"> <text/> </element> </define> </grammar>
In XML Schema, you can only append a new content model at the end of the base type. This restriction doesn't apply to RELAX NG. For example, you can prepend additional elements as follows:
<grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="1.0"> <start> <element name="Root"> <ref name="BarType"/> </element> </start> <define name="BarType"> <element name="header"><text/></element> <ref name="FooType"> <xjc:super/> </ref> <element name="footer"><text/></element> </start> <define name="FooType"> <element name="fooContent"> <text/> </element> </define> </grammar>
<xjc:interface> customization is another way to introduce an inheritance hierarchy in a way similar to the substitution group of W3C XML Schema. This customization can take the optional name attribute.
In many XML vocabularies, it is common to write a schema such as the following to represent a concept of "list" group:
Therefore, it would be desirable if the XJC binding compiler
could generate the ListBlock
interface and have
OrderedList
, ItemizedList
, and
SomeOtherTypeOfList
interfaces implement the
ListBlock
interface.
This can be done by specifying a <xjc:interface>
customization as follows:
<define name="listBlock">
<xjc:interface />
<choice>
<ref name="orderedList"/>
<ref name="itemizedList"/>
<ref name="someOtherTypeOfList"/>
</choice>
</define>
This customization will generate an empty interface with the specified or derived name and have the subordinates implement this interface.
This customization can be also applied to <choice> itself, as shown:
<element name="package">
...
<element name="shipTo">
<choice>
<xjc:interface name="Address" />
<ref name="DomesticAddress"/>
<ref name="InternationalAddress"/>
</choice>
</element>
...
</element>
The effects of this customization are:
Address
interface is generated.DomesitcAddress
and
InternaltionalAddress
will implement this
interface.Package
class will have
Address getShipTo()
and
void setShipTo(Address)
methods.
There is no need for this customization and its child
definitions to be separated by a <ref />
element. Definitions of DomesticAddress
and
InternationalAddress
can just be inlined.
<element name="package">
...
<element name="shipTo">
<choice>
<xjc:interface name="Address" />
<element name="DomesticAddress">
... definition of domestic address ...
</element>
<element name="InternationalAddress">
... definition of international address ...
</element>
</choice>
</element>
...
</element>