JavaTM Architecture for XML Binding
Experimental RELAX NG support

  1. Overview
  2. Synopsis
  3. Supported Customization
    1. <jaxb:schemaBindings>
    2. <jaxb:class>
    3. <jaxb:property>
    4. <jaxb:javaType>
  4. Extension Customization
    1. <xjc:super>
    2. <xjc:interface>

Overview

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.

Synopsis

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.

Supported Customization

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.

<jaxb:schemaBindings>

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.

<jaxb:class>

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>

<jaxb:property>

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>

<jaxb:javaType>

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 ":"");
    }
}

Extension Customization

This section describes other customizations designed specifically for RELAX NG.

<xjc:super>

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>

<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:


<define name="listBlock">
  <choice>
    <ref name="orderedList"/>
    <ref name="itemizedList"/>
    <ref name="someOtherTypeOfList"/>
  </choice>
</define>

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:

  1. The Address interface is generated.
  2. DomesitcAddress and InternaltionalAddress will implement this interface.
  3. The 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>

$Revision: 1.7 $
$Date: 2003/09/10 19:02:53 $