JBind 1.2

A Java-XML Data Binding Framework.

Editor:
Dr. Stefan Wachter <stefan.wachter@jbind.org>

Abstract

JBind is a data binding framework linking Java and XML. The framework consists of a schema compiler for generating Java sources and a runtime environment. The runtime environment is used for unmarshalling (reading) and marshalling (writing) XML documents, for validation, and for accessing and manipulating XML data.

In addition, JBind introduces the concept of XML code that is the result of adding behaviour to XML data. XML code is the seamless integration of manually implemented methods with sources generated by the schema compiler. XML code offers great possibilities for application, framework, and configuration developments.

JBind supports nearly 100% of the W3C XML schema recommendation of 2 May 2001 (cf. 5 Conformance and Extensions). Instance documents are validated against their schema when they are unmarshalled. Simple constraints, i.e. constraints that consider only single attributes or simple content of elements, are enforced during manipulation. Global constraints, e.g. constraints that consider the occurence of attributes/elements or identity constraints, can be checked by an explicit API call.

Status of this Document

This document is in progress. Please send comments to the author. Not only comments regarding the content but also comments regarding the form and the language are welcome.

Table of Contents

1 Introduction
    1.1 Consistency
    1.2 Adding Behaviour to Data
    1.3 XML Meta Data
    1.4 Domain Specific Languages and Application Frameworks
    1.5 Processing
    1.6 A Word of Care - Relating JBind to other Data Binding Frameworks
2 Using JBind
3 Schema Compiler
    3.1 Generated Sources
    3.2 Invoking the Schema Compiler
    3.3 Parameterizing the Code Generation
        3.3.1 Symbol Space Subpackages
        3.3.2 Prefixes and Suffixes for Class/Interface Names
        3.3.3 Accessor Methods
        3.3.4 Other Binding Attributes
    3.4 Example Schema
    3.5 Schema Adjunct Documents
4 Data Model
    4.1 Datatype Hierarchy
    4.2 Data Storage
    4.3 Implementation
    4.4 Manipulating XML Data
        4.4.1 Validation
        4.4.2 Adding, Creating, and Removing
        4.4.3 Wildcard Attributes and Elements
5 Conformance and Extensions
    5.1 Missing Features
    5.2 Extensions
        5.2.1 Identity Constraints on Types
        5.2.2 XPath Constraints
        5.2.3 XPath Methods
        5.2.4 References between Instance Documents
6 XML Code
    6.1 "Hello World!"
    6.2 BabelFish SOAP Client
    6.3 Maze Game
7 JBind Configuration
    7.1 Validation Options
    7.2 ClassLoader Configuration
    7.3 Regular Expressions
    7.4 XPath
    7.5 Data Implementation Factory
    7.6 Namespace to Package Mapping
    7.7 Entity Resolver, Import, and Include
    7.8 How Instances are Linked with their Schemas

Appendices

A Installation
B Glossary
C References
D Acknowledgements

End Notes


1 Introduction

This introduction gives a brief summary of the advantages and possibilties that data binding offers and how they can be leveraged using JBind.

1.1 Consistency

When writing applications that process XML data a common problem is to ensure consistency between the XML data and the code that processes the data. Validating XML parsers play an important role here because they can check that XML data is valid according to its schema. Yet, they can not guarantee that the code that does the further processing is prepared to process that kind of data.

This is where data binding comes in. Data binding takes as its input a schema and generates code that reflects the schema. In other words, data binding is a means to transport the information contained in a schema into programming languages. Thereby consistency between a schema and its processing code is guaranteed.

In general, the more complicated the XML data is the more difficult is to ensure the consistency. JBind supports nearly 100% of the XML schema recommendation. Therefore it can be used in situations with rather complex XML data.

1.2 Adding Behaviour to Data

XML schema is a great possibility to describe the data aspect of an application. Yet, that data has no behaviour (or semantic/meaning). One possibility to add behaviour is to add it from "outside" by having code that interprets the data. Data binding allows another possibility namely to add behaviour directly to the data. This is done by augmenting the generated code with methods.

Having data and its behaviour together the result is nothing else than objects in terms of object oriented programming. At this point it is of great advantage that XML schema is object oriented with respect to two central features: inheritance and polymorphism. This allows a natural mapping of XML schemas into object oriented code.

JBind introduces the concept of XML code that allows the seamless integration of manually implemented behavioural code with generated code that reflects the data aspect (cf. 6 XML Code). Having XML data augmented with behaviour lots of possibilities open for developers.

1.3 XML Meta Data

This topic is closely related to the first two mentioned topics namely "Consistency" and "Adding Behaviour to Data" but adds another twist. Several reasons cause the usage of XML meta data in applications:

  1. Information that is explicitly available in form of XML meta data can easily be used by different parts of an application. Thereby meta data can help to guarantee the consistency between different parts of an application. (Think of a web application where some HTML input fields must match the fields in a relational database.)

  2. Information that is available explicitly in form of meta data is less error-prone than the same information contained implicitly in (lots of) source code. If meta data is stored in XML documents then it can be validated using a parser.

  3. Meta data makes applications configurable thereby allowing non-programmers to modify the application. If the configuration data also contains behaviour then the applications are also easily extensible.

Conventional applications that use meta data are often more complicated at first sight than corresponding hardwired applications because the use of meta data comes with additional complexities. JBind eases the use of meta data essentially. The ability of JBind to generate methods that access referenced data (reflecting attributes of type IDREF and IDREFS or keyref constraints) allows to adequately handle not only meta data that has a simple hierarchical structure but also meta data that has an arbitrary structure. There is no more reason to hardwire specific data and behaviour in applications.

1.4 Domain Specific Languages and Application Frameworks

In case that not only a single application is to be developed but a whole family of applications the use of a domain specific language bears lots of advantages. XML schema can be used to describe the syntax of a domain specific language and JBind can be used to define its (operational) semantic by adding behaviour code.

The extensibility mechanisms of XML schema allows to carry on this idea to full fledged application frameworks. An application framework can be defined by an XML schema with the types having default behaviour. An instance document of the framework schema corresponds to an (executable) application. The framework schema can easily be extended by deriving new customized types from the framework types and using them in framework instance documents.

Note:

The development of a Web-Application framework based on JBind may be a promising endeavour. In fact, the author has already gathered quite an experience in developing a Web-Application framework using similar ideas.

1.5 Processing

At the time being most people familiar with XML techniques agree that XML is the ideal way to exchange data between applications whereas the use of XML inside applications is not that clear. Using generic data structures like [DOM] is awkward. Therefore applications often internally use data structures that are better suited for their processing needs but have to be converted into XML when they are to be exchanged.

JBind allows to have data structures that are well suited for internal processing and that are in an XML form at the same time. Another benefit of having the internal data in an XML form is the ease of using powerful XML techniques like XPath/XSLT not only for exchange (and rendering) but also for internal processing (cf. 5.2.3 XPath Methods and 6.3 Maze Game for an XSLT example).

1.6 A Word of Care - Relating JBind to other Data Binding Frameworks

The main focus of JBind is to ease the intergration of manually written code with generated code and to support nearly all of the XML schema specification. Performance is not a primary design goal of JBind.

Java-XML data binding links the Java world with the XML world. Most data binding frameworks have a major focus on the Java part of the story whereas the XML part is often a compromise with respect to complexity, usability, and performance. JBind clearly has its focus on the XML part which caused some compromises at the Java side.

Yet, JBind allows to plug-in so called cartridges that are responsible for code generation. The cartridges are provided with easily usable information about the schemas to be processed. Developers interested in developing/contributing new cartridges may contact the author.

2 Using JBind

JBind contains the following classes that provide easy access to its functionalities:

classdescription
org.jbind.xml.schema.compiler.Compiler Compiles XML schemas.
org.jbind.xml.facade.Validator Validates XML schemas and instance documents.
org.jbind.xml.ant.CompileTask Ant task for compiling schemas (cf. 3.2 Invoking the Schema Compiler).
org.jbind.xml.ant.ValidateTask Ant task for validating schemas and instance documents. The documents to validate can be specified by a file attribute, a url attribute, or a nested fileset. The isXsd attribute determines if documents are checked to be a valid schema or a valid instance document. If the isXsd attribute is not specified then documents whose name end with ".xsd" are assumed to be schema documents whereas all other documents are assumed to be instance documents.
org.jbind.xml.ant.ExecuteTask Ant task for executing application code.
org.jbind.xml.facade.JBindFacade Provides easy access to JBind functionalities. The functionalities include marshalling, unmarshalling, validation, data comparison, creation of SAXSources to output data, configuration, and application execution.
org.jbind.xml.code.IApplicationCode Encapsulates XML applications.
org.jbind.xml.code.IConfigurationCode Encapsulates XML configuration code.
org.jbind.xml.schema.cmp.Schemas Singleton that provides access to schemas within the virtual machine.
org.jbind.xml.Config Configures JBind.

JBind uses an XML parser of its own to access XML data. This parser supports the [Namespace 1.1] and [XInclude] candidate recommendations.

3 Schema Compiler

The schema compiler processes a schema by generating classes/interfaces for the types contained in the schema. Element and attribute declarations contained in types are reflected by corresponding accessor methods. The generated sources can be placed into different subpackages corresponding to the different symbol spaces of XML schema. There are 5 relevant symbol spaces: types, attributes, elements, attribute groups, and element groups (model groups).

Global types are mapped into classes/interfaces in the types subpackage. An anonymous type that appears inside a local attribute or element declaration is mapped into a static inner class/interface inside the class/interface of the type that contains the declaration. If an anonymous type appears inside a global attribute or element declaration then the class/interface for that type is generated in the subpackage for attributes/elements. If anonymous inner types appear inside an attribute group or element group then a container class is created for the group (in the corresponding subpackage) that contains the static inner classes/interfaces of all anonymous types contained in that group.

3.1 Generated Sources

Given an XML schema four kinds of sources are generated:

  1. [Definition: Data interfaces that contain declarations of accessor methods for the attributes and elements of a type, declarations of methods to access referenced data, and declarations of methods that are based on XPaths. In addition, if an enumeration constraint is imposed on a type then corresponding constants are generated. Data interfaces must not be edited manually because they are overwritten by the code generator. ]

    The generated sources include JavaDoc describing all attributes and all kinds of elements of a type. Additional JavaDoc can be supplied by documentation elements. The xml:lang attribute of such documentation elements must have the value "x-javadoc" in order that the documentation is recognized as being JavaDoc. They may appear inside type definitions or attribute/element declarations. The content inside documentation elements must not contain any markup. In other words, only plain text is allowed. The text is directly copied into the generated source. If some markup is necessary then the text must be in a CDATA section (<![CDATA[...]]>). In addition, each generated method declaration is commented.

  2. [Definition: Behaviour interfaces that are derived from the corresponding data interfaces and contain declarations of manually added methods. Behaviour interfaces are generated only once by the code generator and will never be overwritten. ] If a behaviour interface already exists then the schema compiler checks if the interface declaration is up to date, i.e. that it machtes the inheritance hierarchy in the schema.

    No behaviour interfaces are generated for anonymous types.

  3. [Definition: Behaviour classes that inherit from the behaviour classes of their base types and from the corresponding behaviour interfaces. Behaviour classes are abstract classes where the additional methods declared in the behaviour interfaces are (manually) implemented. They are abstract because the methods declared in the data interfaces are not implemented here. Behaviour classes are generated only once by the code generator and will never be overwritten. ] Exactly like for behaviour interfaces the schema compiler checks that the declarations of behaviour classes match the inheritance hierarchy in the schema.

    No behaviour classes are generated for anonymous types.

  4. [Definition: Data classes that inherit from the corresponding behaviour classes and that normally implement the accessor methods defined in the corresponding data interfaces. A data class is abstract if its type in the schema is defined to be abstract. In this case no accessor methods are generated. Yet, the data class is generated if it contains static inner classes for its anonymous inner types. Data classes must not be edited manually because they are overwritten by the code generator. ]

Data Interface
^
|
extends
|
|
Behaviour Interface
^
|
implements
|
|
Behaviour Class
^
|
extends
|
|
Data Class

Note:

In principle, the code generation is configurable by so called cartridges. [Definition: A cartridge can be plugged into the schema compiler and is responsible for generating a certain kind of source.] Currently there are 4 cartridges corresponding to 4 kinds of generated sources. However, this part of JBind is not well documented and has to mature. This might be a further direction of development of JBind if the user community demands that feature.

The graphic contains the UML diagram of an example that shows the relationship between the four kinds of generated sources. The schema of this example is presented in section 3.4 Example Schema. The names of interfaces have the prefix "I" and the names of data classes/interfaces have the suffix "Data". The graphic demonstrates that the behaviour class/interface of a type can be missing. In this case the inheritance hierarchy uses the next available class/interface that follows in the hierarchy. An abstract type is also contained in the example for which no data class is generated.

Diagram of Inheritance Hierarchy

The design goal of the inheritance hierarchy was to have a separation between the always generated parts that reflect the data aspect of a type and the manually implemented parts that add behaviour. (The methods declared in data interfaces are already available for usage in the derived behaviour classes.)

3.2 Invoking the Schema Compiler

The schema compiler is invoked by the command line:

java org.jbind.xml.schema.compiler.Compiler -schemaUrl <url> [-validateOnly]
  [-package <package>] [-destinationDir <dir>] [-dataDir <dir>] [-behaviourDir <dir>]
where optional arguments are enclosed in square brackets. The arguments are:
  • schemaUrl: A url to an XML schema.

  • validateOnly: If specified then the schema and code generation is validated only. No code is output.

  • package: The Java package that contains the generated classes/interfaces.

  • destinationDir: Used for data and behaviour classes/interfaces if no more specific directory is specified.

  • dataDir: Used as destination directory for data classes/interfaces.

  • behaviourDir: Used as destination directory for behaviour classes/interfaces

If no destination directory is specified then the data directory and the behaviour directory must be specified. If JBind is used together with Ant then a convenient alternative for invoking the schema compiler is to use an Ant task. The provided task has the following attributes and can process nested file sets to select schema files:
  • url: A url to an XML schema.

  • file: A file containing an XML schema.

  • package: The Java package that contains the generated classes/interfaces.

  • destinationDir: Used for data and behaviour classes/interfaces if no more specific directory is specified.

  • dataDir: Used as destination directory for data classes/interfaces.

  • behaviourDir: Used as destination directory for behaviour classes/interfaces

  • derivePackages: Boolean attribute that is only relevant if file sets are used. The default is false. If this attribute is false then the schemas selected by file sets get the package specified by the package attribute. If this attribute is true then the package of a schema contained in a file set is derived from its relative location in the file set. In other words, the subdirectory hierarchy of a file set is translated into a corresponding package hierarchy.

A code snippet from the JBind build file with a target that compiles the well known XML namespace schema and another target that compiles all example schemas demonstrates the usage. The class path that is referenced in the taskdef element must contain the JBind library and the necessary external libraries (cf. A Installation).

<taskdef name="jbind" classname="org.jbind.xml.ant.CompileTask" classpathref="jBind"/>

<target name="xml98Schema" depends="taskDef">
  <jbind url="http://www.w3.org/2001/xml.xsd" destinationDir="${genSrcDir}"/>
</target>
          
<target name="generateExamples" depends="taskDef">
  <jbind  dataDir="${genExamplesSrcDir}" behaviourDir="${examplesDir}" derivePackage="true">
    <fileset dir="${examplesDir}" includes="**/*.xsd"/>
  </jbind>
</target>

3.3 Parameterizing the Code Generation

Code generation is mainly parameterized by attributes that appear inside schema documents. XML schema allows the appearance of arbitrary attributes at nearly all tags as long as they do not belong to the http://www.w3.org/2001/XMLSchema namespace. This feature is used in JBind to add binding information to schemas. [Definition: Let the JBind namespace be "http://www.jbind.org"]. [Definition: A binding attribute is an attribute that belongs to the JBind namespace.] All binding attributes are declared in the JBind schema jBind.xsd.

It is possible to have a schema and its binding information in separate documents. This approach is explained in section 3.5 Schema Adjunct Documents. However, this approach consists of generating a new schema based on an original schema by augmenting it with binding information. The result is a schema that contains the binding attributes that are described in this section.

[Definition: Some binding attributes have an effect only on the tag at which they appear. They are called local binding attributes.] [Definition: Other binding attributes are propagated along nested tags. They are called propagating binding attributes.] In general, local binding attributes are only allowed on dedicated tags for which they bear binding information whereas propagating binding attributes may appear on any tag. Finally there are [Definition: defaulted binding attributes that take their default value from the schema element they are nested in. If a schema is included by another schema then the including schema is also considered.]

The situation is slightly more complicated for attribute and element declarations that are references to other declarations. In this case if a binding attribute is accessed then first the binding attributes of the declaration itself are considered and then - only if no matching attribute was found - the binding attributes of the referenced declaration.

[Definition: All classes/interfaces that are generated for a schema are placed into a common package that is called the schema package]. The schema package can be specified by

  1. an argument on the command line,

  2. a local binding attribute on the schema tag, or

  3. a mapping of namespaces to package names in the JBind configuraiton (cf. 7.6 Namespace to Package Mapping).

The different possibilities have the above precende, i.e. a package argument on the commandline overrules a package defined in the schema tag that in turn overrules the namespace to package mapping.

If the name of a type contains one or more dots then the name is split into two parts: 1. A prefix reaching until the last dot and 2. a suffix starting after the last dot. The prefix is used to denote a subpackage inside the schema package whereas the suffix is used for the names of the generated classes/interfaces inside their package.

3.3.1 Symbol Space Subpackages

The generated code can be placed into different subpackages depending on symbol spaces. Five binding attributes determine the subpackages. These binding attributes can occur inside a schema tag.

attributedefault
typeSubPackage
attributeSubPackageattribute
elementSubPackageelement
attrGroupSubPackageattrGroup
elemGroupSubPackageelemGroup

Note:

The default configuration uses no subpackage for (global) types. This means their files are placed direclty in the schema package. In order to avoid name conflicts, the files of all other symbol spaces are placed in subpackages of their own. If other symbol spaces are also placed directly in the schema package by assigning an empty string to the corresponding binding attribute then care must be taken that the names do not conflict.

3.3.2 Prefixes and Suffixes for Class/Interface Names

The prefixes and suffixes used for the various generated sources can be configured by 8 binding attributes that can appear in the schema tag. The names of these binding attributes are created by selecting an entry from the cartridge column in the following table and appending either "Prefix" or "Suffix". For example to set the data class prefix the binding attribute dataClassPrefix is used. The table shows the default values for these binding attributes.

cartridgeprefixsuffix
dataInterfaceIData
dataClassData
behaviourInterfaceI
behaviourClass

3.3.3 Accessor Methods

Several binding attributes control the generation of accessor methods. [Definition: Accessor methods are based on the properties of a type, i.e. on its attribute/element declarations and on its reference constraints]. [Definition: Each property has a property name. In case of an element/attribute declaration the property name is equal to the name of the declaration. In case of a reference constraint the name is either equal to the name if the referencing attribute or to the name of the reference constraint. Property names may be overloaded by the name binding attribute.] The names of the generated methods are of the form "<prefix><propertyName>" where the first letter of the property name is capitalized.

Some binding attributes determine if specific methods are generated and in what form. These attributes are propagating binding attributes. They can take one of three possible values: normal, hook, or none. The value normal causes the generation of matching method declarations in the data interfaces and method implementations in the data classes. The value hook causes that method declarations are generated in the data interfaces like in the "normal" case. The difference is that these methods are not implemented in the data classes. Instead, the names of the generated methods in the data classes have the prefix "do" indicating that they are hook methods. The actual methods have to be implemented manually in the behaviour classes. Normally these implementations will use the generated hook methods.

The following table gives an overview of these binding attributes together with their default values and prefixes of the generated methods.

attributedefaultprefixdescription
getternormalgetGets an attribute or element. Generated only for elements that have a maxOccurs of 1.
setternonesetSets an attribute.
creatornonecreateCreates an element.
creatorWithTypenonecreateCreates an element. Allows to specify the type of the element (the so called overloading type). The overloading type must be a subtype of the declared element type.
removernoneremoveRemoves an attribute or element. Generated only for elements that have a maxOccurs of 1.
checkernonehasChecks the presence of an attribute or element. Generated only for elements that have a maxOccurs of 1.
iteratornormaliterIterates the items of list valued attributes or elements. Generated only for attributes that have a list type and elements that have a maxOccurs greater than 1. If elements are iterated then the method name uses the plural form of the property name.
refGetternormalrefGets referenced data. Data is referenced by attributes of type IDREF or by types that have a keyref constraint (cf. 5.2.1 Identity Constraints on Types).
refsIteratornormalrefsIterates referenced data. Data is referenced by attributes of type IDREFS or by types that have a keyref constraint (cf. 5.2.1 Identity Constraints on Types).

Note:

No accessor methods are generated for wildcard attributes or wildcard elements. They can be accessed by inherited methods (cf. 4.4.3 Wildcard Attributes and Elements).

Note:

If a type has an identity constraint then either a reference getter or a reference iterator method may be generated depending on the selector XPath. If the selector XPath is guaranteed to return only one data object then a getter method is generated and an iterate method otherwise. The analysis if the selector XPath returns only a single data object depends on the used XPath implementation (cf. 7.4 XPath). The analysis may be very sophisticated or may simply check if an XPath equals ".".

Note:

Elements of type IDREF or IDREFS also reference data. Yet, no special accessor methods are generated because the corresponding methods are already defined in the interfaces IIDREFData and IIDREFSData. In other words, to access data objects that are referenced by elements of type IDREF or IDREFS first the elements must be accessed and then the corresponding methods of the elements must be called.

Other binding attributes control the types used for accessor methods:

attributeoccurrencedescription
useDataClass propagating binding attribute Boolean attribute that determines if the data class or the simple storage type of an accessed property is used. If set to true then the data class is used. If set to false (that is the default) then the simple storage type is used if the property is an attribute or an element with a simple type. If an element has a complex type then its data class is used regardless of the useDataClass attribute. If a property with a primitive Java type is iterated then the corresponding wrapper class is used (e.g. a double is wrapped in a Double object). Attribute setter methods always use the simple storage type.
referencedType attribute declarations, type key, type unique, and type keyref constraints (cf. 5.2.1 Identity Constraints on Types), fetch XPath method (cf. 5.2.3 XPath Methods) Determines the type that is returned by reference getter methods.

Note:

If the useDataClass binding attribute is set to false then the generated methods access the simple storage values. In case that a simple storage value has a primitive Java type a NullPointerException is raised if the accessed attribute or element is not present. It is recommended to generate check methods that can be called before such a simple storage value is accessed. In case that a simple storage value has a reference type and but its attribute or element is not present null is returned.

3.3.4 Other Binding Attributes

attributeoccurrencedescription
hasBehaviour defaulted binding attribute Boolean attribute that controls the generation of behaviour interfaces and behaviour classes. The default is false.
name all "named" tags and enumeration facet tags Changes the name that is used for code generation. If this attribute is not specified then the XML schema name attribute is used or - in case of anonymous types - an automatically generated name. In case of enumeration facets the names of the generated Java constants can be set. If no name is specified then the constant name is derived from the value by converting all lower case letters into upper case letters and by replacing invalid characters by underscores.
package schema and import tag Determines the package of the generated classes/interfaces.
factoryType schema tag Determines the type of the schema factory.

Note:

All names that are used in generated code are translated into valid Java identifiers. This translation simply replaces invalid characters by underscores. If a name starts with a character that would be valid inside a Java identifier (e.g. a number) but that is not valid at the beginning then the name is prefixed by an underscore.

3.4 Example Schema

The following example schema shows the usage of various binding attributes. Looking at the UML diagram presented previously shows that no data class is generated for the MeansOfTransport type and that no behaviour class and no behaviour interface for the Automobile type. This is caused by the fact that the MeansOfTransport type is defined to by abstract and that the Automobile type is defined to have no behaviour.

The attribute manufacturer of the Vehicle type is of type IDREF. This causes the schema compiler to generate the method "IManufacturerData getManufacturer()" to access the referenced manufacturer.

<?xml version="1.0" encoding="UTF-8"?>
<schema
  elementFormDefault="qualified"
  targetNamespace="meansOfTransport"
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:jb="http://www.jbind.org"
  xmlns:t="meansOfTransport"
  jb:package="meansOfTransport"
	jb:elementSubPackage=""
  jb:hasBehaviour="true" jb:setter="normal" jb:checker="normal"
  jb:factoryType="Factory">

  <complexType name="MeansOfTransport" abstract="true">
    <annotation>
      <documentation xml:lang="x-javadoc"><![CDATA[
        Base class for all kinds of <i>means of transport</i>.
      ]]></documentation>
    </annotation>
  </complexType>

  <complexType name="Vehicle">
    <complexContent>
      <extension base="t:MeansOfTransport">
        <attribute name="numberOfWheels" type="int"
          jb:setter="hook" jb:remover="normal">
          <annotation>
            <documentation xml:lang="x-javadoc">
              This attribute is set by a hook method that is manually implemented
              in the {@link Vehicle} class.
            </documentation>
          </annotation>
        </attribute>
        <attribute name="manufacturer" type="IDREF" jb:referencedType="t:Manufacturer"/>
      </extension>
    </complexContent>
  </complexType>

  <complexType name="Automobile" jb:hasBehaviour="false">
    <complexContent>
      <extension base="t:Vehicle">
        <attribute name="fuelType" type="string" use="required" jb:checker="none"/>
        <attribute name="consumptionInLitres" type="decimal" jb:name="consumption"/>
        <sequence>
          <element ref="t:engine"/>
        </sequence>
      </extension>
    </complexContent>
  </complexType>

  <complexType name="Truck">
    <complexContent>
      <extension base="t:Automobile">
        <attribute name="loadCapacityInTons" type="decimal"/>
      </extension>
    </complexContent>
  </complexType>

  <element name="meansOfTransport" type="t:MeansOfTransport" abstract="true"/>
  <element name="vehicle" type="t:Vehicle" substitutionGroup="t:meansOfTransport"/>
  <element name="automobile" type="t:Automobile" substitutionGroup="t:vehicle"/>
  <element name="truck" type="t:Truck" substitutionGroup="t:automobile"/>
	
  <element name="engine"/>
	
  <complexType name="Manufacturer" jb:hasBehaviour="false">
    <attribute name="id" type="ID"/>
  </complexType>

	<element name="manufacturer" type="t:Manufacturer"/>

  <element name="manufacturers">
    <complexType>
      <sequence maxOccurs="unbounded">
        <element name="manufacturer" type="t:Manufacturer"/>
      </sequence>
    </complexType>
  </element>
	
  <element name="meansOfTransports">
		<complexType>
			<sequence maxOccurs="unbounded">
				<element ref="t:meansOfTransport"/>
			</sequence>
		</complexType>
	</element>
  
  <!--
    Factory type that has creation methods for vehicles, automobiles, trucks, and manufacturers.
		The content model of a factory may contain only references to top-level element declarations.
  -->
  <complexType name="Factory" jb:hasBehaviour="false" jb:getter="none" jb:creator="normal">
    <sequence>
      <element ref="t:vehicle"/>
      <element ref="t:automobile"/>
      <element ref="t:truck"/>
      <element ref="t:manufacturer"/>
    </sequence>
  </complexType>

</schema>

See the sources and the JavaDoc. The vehicle class is inserted here for convenience to show an example of a hook method:

package org.jbind.example.meansOfTransport;

import org.jbind.xml.msg.XmlException;

public abstract class Vehicle extends MeansOfTransport implements IVehicle {
  /**
   * Implementation of the setter using the hook method.
   */
  public void setNumberOfWheels(int anInt) throws XmlException {
    doSetNumberOfWheels(anInt);
  }
  /**
   * Declaration of the hook method. The hook method is implemented by the
   * generated data class.
   */
  protected abstract void doSetNumberOfWheels(int anInt) throws XmlException;
}

3.5 Schema Adjunct Documents

Section 3.3 Parameterizing the Code Generation showed how binding attributes are included in schema documents to parameterize the code generation. This approach works fine if the schema to be bound can be modified to fit the needs of JBind. If a schema can not be modified or the schema is to be shared by several parties with some of them not using JBind then another approach is needed that leaves schema documents untouched.

[Definition: Schema adjunct documents are used by JBind to store binding information for schema documents in separate documents.] This has the advantage that schema documents have not to be touched and that binding information is not scattered all over schema documents. Schema adjunct documents are governed by the jBind-schema-adjunct.xsd schema from which a part is repeated here for convenience:

<complexType name="Adjunct">
  <choice minOccurs="0" maxOccurs="unbounded">
    <any namespace="http://www.jbind.org" processContents="strict"/>
    <element name="adjunct" type="t:Adjunct"/>
  </choice>
  <attribute name="select" use="required">
    <simpleType>
      <restriction base="string">
        <pattern value="[^/].*"/>
      </restriction>
    </simpleType>
  </attribute>
  <attribute name="checkForEmptySelection" type="boolean" default="true"/>
  <anyAttribute namespace="http://www.jbind.org" processContents="strict"/>
</complexType>

<element name="adjuncts">
  <complexType>
    <sequence>
      <element name="adjunct" type="t:Adjunct" minOccurs="0" maxOccurs="unbounded"/>
    </sequence>
  </complexType>
</element>

A schema adjunct document contains arbitrarily nested adjunct elements. Each adjunct element has a required select attribute that holds a relative XPath to select parts of a schema document. The XPaths of top-level adjunct elements are evaluated relative to the document root of a schema document whereas the XPaths of nested adjunct elements are evaluated relative to the selected parts of their parent adjunct elements. The optional checkForEmptySelection attribute controls if an adjunct element with an empty selection is reported. This attribute is useful to detect errors in adjunct documents.

An adjunct element can bear arbitrary binding attributes. and can contain arbitrary extension elements. These are copied into the parts of a schema document that are selected by the corresponding adjunct element. Binding attributes are directly copied whereas extension elements are copied into an annotation/appinfo element. If a selected part has already an annotation element then an additional appinfo element containing the extension elements is appended to the content of the annotation element.

The current implementation for processing schema adjunct documents consists of generating new schema documents. [Definition: A bound schema is the result of applying binding information contained in a schema adjunct document to a schema document.] A bound schema can be registered in the JBind configuration to be used whenever its original schema is addressed (cf. 7.7 Entity Resolver, Import, and Include).

The process of applying binding information contained in schema adjunct documents to schema documents is implemented by a 2 step stylesheet transformation. In the first step, a schema adjunct document is transformed into a stylesheet called the adjunct stylesheet that contains all binding information and knows how to process schema documents accordingly. In the second step, the adjuct stylesheet is applied to a schema document. In principle, a schema adjunct document can contain binding information for several schemas and a schema may be bound by applying several schema adjunct documents sequentially.

This process is illustrated in the next figure. The schema adjunct document adjunct.xml is transformed into the adjunct stylesheet adjunct.xsl by the transformAdjunct.xsl stylesheet. Then the adjunct stylesheet is used to transform the schema document schema.xsd into its bound version bound-schema.xsd.

Schema Adjunct Process

4 Data Model

4.1 Datatype Hierarchy

The datatype hierarchy of XML schema is defined in chapter built-in datatypes in the XML schema specification. A graphic from that chapter is inserted here for convenience.

Diagram of built-in type hierarchy

Datatypes are represented internally by instances of generic type classes. These classes are instantiated either in static setup code (for the built-in types) or when a schema is read in. The corresponding interfaces can be found in the package org.jbind.xml.core.type.

[Definition: Data types that are derived from anySimpleType have a simple storage type. This is the type used to store values of the corresponding type. Simple storage types are either primitive types (like int or double) or they are (simple) reference types (like String or BigDecimal).] Types that are not derived from a simple type, i.e. complex types with a complex content model have no simple storage type. Complex types with a simple content model have the same simple storage type as their content type.

4.2 Data Storage

[Definition: Classes/interfaces that are responsible for the storage of values are called storage classes/interfaces]. [Definition: Corresponding to the datatype hierarchy there is a hierarchy of these classes/interfaces that is called the storage hierarchy]. The framework contains interfaces for all built-in storage classes that can be found in the package org.jbind.xml.core.data.

The data classes/interfaces that are generated by the schema compiler are derived from storage classes/interfaces. In other words, each generated class/interface has an ancestor amongst the classes/interfaces of the package org.jbind.xml.core.data. This also true for data classes/interfaces of complex types. If a complex type has complex content then it is derived from anyType. If the type has simple content then its storage class/interface is derived from the storage class/interface of its simple content type.

[Definition: Each storage class whose type is derived from anySimpleType has a simple storage value. A simple storage value is for example an int or a String.] The simple storage values can be accessed by getter and setter methods of the storage classes. For example the interface of the int storage class is:

/*
 * JBind
 *
 * Copyright (c) by Stefan Wachter. All rights reserved.
 *
 * Usage, modification, and redistribution is subject to license terms that are
 * available at 'http://www.jbind.org'. The JBind license is like the
 * 'Apache Software License V 1.1'.
 */
package org.jbind.xml.core.data;

import org.jbind.xml.msg.XmlException;

public interface IIntData extends ILongData {
  int getInt();

  void setInt(int aValue) throws XmlException;
}

The storage classes can be called wrapper classes for the simple storage values. The reason for introducing wrapper classes is that the datatype hierarchy should be reflected by the storage hierarchy.

Note:

There are subtle problems when mapping the built-in XML datatypes into corresponding Java classes. Consider the XML byte type that is a restriction of the XML short type that in turn is a restriction of the XML int type until the anySimpleType is reached. The storage class of the XML byte type has as its simple storage type the primitive Java type byte. Accordingly, it has the accessor methods "byte getByte()" and "void setByte(byte aByte)".

The XML byte type must also have the accessor methods "int getInt()" and "void setInt(int anInt)" because it is derived from the XML int type. These methods are implemented by casting integers into bytes and vice versa. Similar conversions have to be done all the way up in the storage hierarchy.

Another problem is that two simple values can be equal only if they have the same built-in primitive type or if their types are derived from the same built-in primitive type. Simple values whose types are not derived from or equal to the same built-in primitive type can not be equal. For example the decimal 123.0 is equal to the byte 123 but is not equal to the string "123". In addition, values that are equal must have the same hash code in order to be usable as keys in hash maps.

4.3 Implementation

The implementation of the storage hierarchy is based on the Bridge Pattern (cf. [GOF]). This pattern consists of an abstraction that uses an implementation. In case of JBind the data classes are the abstraction that is backed by default by a simple nested HashMap structure that plays the role of the implementation. [Definition: The implementation is called the data implementation]. It can be configured by specifying the data implementation factory. (cf. 7.5 Data Implementation Factory).

The data implementation of a data class is accessed using its getImpl_() method. It may be useful to access the underlying data implementation directly for example in order to apply a stylesheet.

Note:

The design decision of using the brige pattern has the advantage that the data classes are decoupled from the underlying data structure. For example it is possible to use an also provided [DOM] implementation instead of the simple HashMap implementation. The advantage of using the DOM implemtation is that a ready to use DOM tree is always in memory. Yet, the disadvantage of the DOM implementation is that it is less performant.

4.4 Manipulating XML Data

XML data should be manipulated by using the generated accessor methods. In principle, it is also possible to manipulate the underliying data implementation directly but the current version of JBind is not thoroughly tested for this kind of use. In addition, nearly no constraints are checked when manipulating the data implementation directly.

4.4.1 Validation

[Definition: During manipulation only local constraints are enforced, i.e. constraint that consider only the simple content of elements or attributes. Amongst these constraints are the inherent constraints of simple types, constraints based on facets, and fixed values.] [Definition: After manipulation the global constraints can be checked by calling the validateData method of the JBindFacade. Global constraints consider XML data as a whole. They contain identity constraints, occurence constraints, and XPath constraints.]

4.4.2 Adding, Creating, and Removing

Studiying the generated accessor methods one may wonder why there are no methods for adding attributes or elements. The reason lies in the relationship between types and declarations in the JBind framework. A type has not enough information to instantiate a data class because it has no information about fixed/default values. Therefore data classes are instantiated using declarations.

The declaration to be used for instantiating a data class depends on the "position" of the data in the XML structure, i.e. it depends on its enclosing data class. XML schema requires that content models must not contain two element declaration with the same name but different types or value constraints. Therefore the element declaration to use for instantiating a data class is not dependent on the index of an element in the sequence of enclosed elements. Therefore if an element is to be added to a data object then the data object is asked to return a corresponding element declaration. Newly created elements are appended to the current content of the data object. Similar comments apply to attributes.

The described approach works fine if there is already a data class to which attributes/elements are added. In order to create an top-level element, i.e. an element that is not enclosed inside a data class another mechanism is needed. [Definition: The schema factory of a schema is used to instantiate top-level data classes.] The schema factory is defined by specifiying its type using the factoryType binding attribute (cf. 3.3.4 Other Binding Attributes). The schema factory acts as a normal data class to create elements. The difference to a normal data class is that the schema factory creates top-level elements. Therefore the content model of a schema factory type must contain only references to top-level elements and no element declarations or element wildcards.

If a factoryType is specified for a schema then an instance of that type is created that can be accessed by the method getFactory() of the schema. The following example shows the usage of a schema factory. The example reuses the schema presented at 3.4 Example Schema.

package org.jbind.example.meansOfTransport;

import java.math.BigDecimal;
import java.net.URL;
import org.jbind.xml.core.cmp.ISchema;
import org.jbind.xml.facade.JBindFacade;
import org.jbind.xml.msg.XmlException;

/**
 * Example showing the usage of the schema factory.
 */
public class TruckCreation {
  public static void main(String[] args) {
    URL url = TruckCreation.class.getResource("meansOfTransport.xsd");
    try {
      ISchema schema = JBindFacade.readSchema(url);
      IFactoryData factory = (IFactoryData)schema.getFactory();
      ITruck truck = factory.createTruck();
      truck.setNumberOfWheels(7);
      truck.setFuelType("water");
      truck.setConsumption(12.0);
      truck.setLoadCapacityInTons(new BigDecimal("30"));
    } catch (XmlException e) {
      e.printStackTrace();
    }
  }
}

JBind allows no indexed access of elements in a content model. The reason is that content models in XML schema are very flexible and allow elements to appear in complex ways for which a simple indexed access seems not to be appropriate. JBind allows only to iterate through elements in document order. Elements that are substitutes (i.e. elements that are in the substitution group of an element contained in a content model) are included in the iteration.

The iterator used is a ListIterator allowing the forward and backward navigation. In addition, elements can be removed by invoking the remove method of the iterator.

Note:

It would be nice to generate classes that reflect the content models and thereby allow to navigate through the content. Such classes would also allow to create new elements at specific positions in a content model. This might be a further direction of development of JBind if the user community demands that feature.

4.4.3 Wildcard Attributes and Elements

Wildcard attributes and elements are accessed by methods inherited from the IAnyTypeData interface. The usage of some of these methods is illustrated in 6.2 BabelFish SOAP Client where the wildcard elements inside SOAP bodies are accessed. The relevant methods are:

methoddescription
IAnyTypeData getAttribute_(String aNamespace, String aName) Gets an attribute.
Iterator iterAttributes_(String aNamespace, String aName) Iterates attributes.
setAttribute_(String aNamespace, String aName, IAnyType anOverloadingType, String aValue) Sets an attribute.
Iterator iterElements_(String aNamespace, String aName) Iterates elements.
createElement_(String aNamespace, String aName, IAnyType anOverloadingType, String aSimpleContent) Creates an element.

5 Conformance and Extensions

The conformance of JBind was checked by using the W3C XML Schema Test Collection available at http://www.w3.org/2001/05/xmlschema-test-collection.html with all the test cases available in July 2002. All test cases were passed except some few test cases that seem to be incorrect. In addition, JBind contains a collection of scenarios that are used to test the schema compiler and that are at the same time additional test cases for conformance.

Therefore to the best knowledge of the author JBind seems to be conformant with the XML schema specification with the exceptions reported in the next section.

5.1 Missing Features

The ENTITY and ENTITIES types are supported only syntactically, i.e. it is only checked that data of type ENTITY or ENTITIES is a valid NCName or a list of valid NCNames, respectively. It is not checked that the NCNames match unparsed entity declarations.

5.2 Extensions

The XML schema specification allows arbitrary elements to appear inside appinfo elements. This mechanisms is used by JBind for extending the expressiveness of schemas and to provide additional information for code generation. [Definition: An extension element is an element in the JBind namespace that appears inside an appinfo element]. The following schema shows the various extension elements of JBind. They are explained in the next sections.

<?xml version="1.0" encoding="UTF-8"?>
<schema
  xmlns="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="qualified"
  xmlns:jb="http://www.jbind.org"
  targetNamespace="helloWorld"
  xmlns:t="helloWorld"
  jb:package="helloWorld">

  <complexType name="Country">
    <annotation>
      <appinfo>
        <jb:key name="cityIndex">
          <selector xpath="t:city"/>
          <field xpath="../@countryId"/>
          <field xpath="@cityId"/>
        </jb:key>
        <jb:xPathMethod name="countrySummary" 
          xpath="concat('country ', @countryName, ' has ', count(t:city), ' cities.')"
          type="string"/>
      </appinfo>
    </annotation>
    <sequence maxOccurs="unbounded">
      <element name="city" type="t:City"/>
    </sequence>
    <attribute name="countryId" type="NMTOKEN" use="required"/>
    <attribute name="countryName" type="string" use="required"/>
    <attribute name="area" type="nonNegativeInteger"/>
  </complexType>

  <complexType name="City">
    <attribute name="cityId" type="NMTOKEN" use="required"/>
    <attribute name="cityName" type="string" use="required"/>
  </complexType>

  <complexType name="Person" jb:hasBehaviour="true">
    <annotation>
      <documentation xml:lang="x-javadoc">
        A person has the method &quot;sayHello&quot;.
      </documentation>
      <appinfo>
        <jb:keyref name="city" refer="t:cityIndex" jb:referencedType="t:City">
          <selector xpath="."/>
          <field xpath="@countryId"/>
          <field xpath="@cityId"/>
        </jb:keyref>
        <jb:xPathConstraint 
          test="(@extraterrestrial='true' and not(@countryId) and not(@cityId)) or (@countryId and @cityId)"/>
      </appinfo>
    </annotation>
    <attribute name="personName" type="string" use="required"/>
    <attribute name="countryId" type="NMTOKEN"/>
    <attribute name="cityId" type="NMTOKEN"/>
    <attribute name="extraterrestrial" type="boolean" default="false"/>
  </complexType>

  <complexType name="World" jb:hasBehaviour="true">
    <annotation>
      <appinfo>
        <!-- Counts all countries. -->
        <jb:xPathMethod name="countries" xpath="count(.//t:country)" type="number"/>
        <!-- Selects all countries. -->
        <jb:xPathMethod name="allCountries" xpath=".//t:country" type="select"/>
        <!-- Counts all persons. -->
        <jb:xPathMethod name="persons" xpath="count(.//t:person)" type="number"/>
        <!-- Selects all persons. -->
        <jb:xPathMethod name="allPersons" xpath=".//t:person" type="select"/>
        <!-- Sums the area of all countries. -->
        <jb:xPathMethod name="totalArea" xpath="sum(.//t:country/@area)" type="number"/>
      </appinfo>
    </annotation>
    <choice maxOccurs="unbounded">
      <element name="country" type="t:Country"/>
      <element name="person" type="t:Person"/>
    </choice>
    <attribute name="nbSetupAndTearDownLevels" type="int" use="required"/>
  </complexType>

  <element name="world" type="t:World"/>

</schema>

5.2.1 Identity Constraints on Types

Key, unique, and keyref identity constraints of XML schema are applicable only on elements and not on types. A natural extension is to allow these constraints also for types with the semantic that each element of such a type is constrained accordingly. Identity constraints on types are specified by three extension elements with the names: key, unique, and keyref. All these elements have the same attributes and content as the corresponding elements for defining identity constraints on elements. Key and unique constraints have an additional scope attribute that is described below.

XPaths in XML schema are of a restricted form. They can only access descendants of nodes and not their ancestors or siblings. JBind allows unconstraint XPaths for selectors and fields in identity constraints on types. This feature allows to handle the situation adequately where some elements are unique inside a specific context, i.e. inside enclosing elements. The key of such elements is simply formed by fields from the elements and their ancestors.

This feature is used in the example schema at the Country type to build an index of cities inside their countries. The relevant definition is repeated here for convenience:

<complexType name="Country">
  ...
  <jb:key name="cityIndex">
    <selector xpath="t:city"/>
    <field xpath="ancestor::*[@countryId]/@countryId"/>
    <field xpath="@cityId"/>
  </jb:key>
  ...
</complexType>

The first field XPath is the interesting one. It selectes amongst the ancestors of a city element that one that has a countryId attribute. (There must be exactly one such element. Otherwise an exception is raised.) It would also have been possible just to access the parent node by the XPath "../@countryId". The first variant is more robust because it is not so dependent on the structure. It still works for example if regions are introduced between countries and their citites.

Note:

An XPath like "ancstor::t:country/@countryId" would also work but is not recommended because the name of elements that will be of type Country is not known. In XPath 2.0 there is a possibility to check elements for their types with an instanceof operator. This will be the preferred solution in future.

The scope attribute of key and unique constraints can take two possible values:

  1. scope="global": This is default. All elements of a type with global key or unique constraint are inserted into a global index for that constraint. Keyref constraints reference entries in this index.

  2. scope="local": A local index is created if an element with a local key or unique constraint is encountered during validation. The created index can be referenced only from the element itself or from descendents of the element. A local key or unique constraint can not be referenced from parent elements or siblings. Sibling elements of the same type have corresponding indices of their own. If an element of the same type occurs as a descendent then the local index is shadowed by a new local index for the descendent element.

    Note:

    Local key or unique constraints are useful if elements are to be indexed in different contexts. No care must be taken that the keys are globally unique. They must only be unique in their subtree.

5.2.2 XPath Constraints

The xPathConstraint extension element uses XPaths to specify constraints on types. The element has two attributes:

  • select. Optional attribute that contains an XPath that is used to select the data objects to be tested. The XPath is evaluated relative to the current data object, i.e. the data object on whose type the XPath constraint is imposed. If no select attribute is present then the current data object is selected.

  • test. An arbitrary XPath that is evaluated to a boolean. The XPathConstraint is statisfied iff its XPath evaluates to true for all selected data objects.

Note:

XPath constraints are equal in concept to the assert mechanism of [Schematron].

The Person type in the example schema uses an XPath constraint to check the cooccurrence of attributes. The select attribute is used only for demonstration because its value corresponds to the default. The relevant part is repeated here for convenience.

<complexType name="Person" jb:hasBehaviour="true">
  ...
  <jb:xPathConstraint select="."
    test="(@extraterrestrial and not(@countryId) and not(@cityId)) or (@countryId and @cityId)"/>
  ...
</complexType>       

5.2.3 XPath Methods

The xPathMethod extension element can be used to have the schema compiler generate methods that evaluate XPaths. The xPathMethod element has the following attributes:

  • name. Required attribute for naming the method.

  • xpath. Required attribute for the XPath to evaluate.

  • type. Optional attribute for specifiying the method type. The method type determines how the result of evaluating the XPath is interpreted. Depending on the method type the generated method has different return types. The method type is also used as a prefix for naming the generated method. The following method types are supported:

    1. select (default). Returns an iterator of the selected data objects.

    2. fetch. Returns a data object that is selected by the XPath. If the XPath selects more than one data object then an exception is raised.

    3. test. The XPath is evaluated to a boolean.

    4. number. The XPath is evaluated to a double.

    5. string. The XPath is evaluated to a String.

    The standard XPath type conversions are used when the evaluation result must be converted.

The example schema contains a number of XPath methods that are used in section 6.1 "Hello World!" and that are not explained here. For demonstration the following concise schema is presented that contains an arbitrary nested element that has a number and a selected attribute. In addition, an instance document and a code snippet that calls the generated XPath methods is shown. Note the namespace prefixes in the XPaths.

<?xml version="1.0" encoding="UTF-8"?>
<schema elementFormDefault="qualified" targetNamespace="xPathMethods"
  xmlns="http://www.w3.org/2001/XMLSchema" xmlns:jb="http://www.jbind.org"
  xmlns:t="xPathMethods">
  <element name="element">
    <complexType>
      <annotation>
        <appinfo>
          <jb:xPathMethod name="allElements" xpath=".//t:element" type="select"/>
          <jb:xPathMethod name="totalSum" xpath="sum(.//t:element/@number)" type="number"/>
          <jb:xPathMethod name="overview" 
            xpath="concat('There are ', count(.//t:element[@selected]), ' selected elements.')"
            type="string"/>
          <jb:xPathMethod name="totalAndSelectedSum"
            xpath="sum(.//t:element/@number) &gt; 2 * sum(.//t:element[@selected]/@number)"
            type="test"/>
          <jb:xPathMethod name="maximum"
            xpath=".//t:element[@number and not(@number &lt; //t:element/@number)]"
            type="fetch"/>
        </appinfo>
      </annotation>
      <sequence>
        <element ref="t:element" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
      <attribute name="number" type="decimal"/>
      <attribute name="selected" type="boolean"/>
    </complexType>
  </element>
</schema>

instance documentjunit test code
<?xml version="1.0" encoding="UTF-8" ?>
<element xmlns="xPathMethods">
  <element number="5"/>
  <element number="13"/>
  <element selected="true">
    <element selected="true" number="10"/>
  </element>
</element>
Iterator i = data.selectAllElements();
i.next(); i.next(); i.next(); i.next(); i.next();
assertTrue("1", !i.hasNext());
double d = data.numberTotalSum();
assertTrue("2: " + d, 28 == d);
String s = data.stringOverview();
assertTrue("3: " + s, "There are 2 selected elements.".equals(s));
assertTrue("4:", data.testTotalAndSelectedSum());
xPathMethods.element.IElementData max =
(xPathMethods.element.IElementData)data.fetchMaximum();
assertTrue("5: ", new BigDecimal("13").equals(max.getNumber()));

Note:

This note is based on ideas that are well-elaborated in [Generative Programming] pp. 259-262.

A common problem with OO programs is the coupling between behaviour and object structure. OO programs tend to contain a lot of small methods that do no or very little computation and call other methods in other objects. This is a consequence of the law of Demeter that states that a method should access only self, local/instance variables, and arguments.

An alternative to having lots of small "information passing" methods is not to obey the law of Demeter and access "remote" objects by invokation chains (e.g. object.part1().part2().part3()). This makes lots of small "information passing" methods unneccessary but at the same time "hardwires" the object structure within methods.

The usage of XPath methods (especially of the select or fetch type) can remedy this dilemma. The object structure can be hidden from methods by defining XPath methods for "remote" object access.

5.2.4 References between Instance Documents

Validation in XML is always concerned only with the validity of single instance documents. A consequence is that attributes of type IDREF or IDREFS or type key ref constraints can only reference data that is contained in the same instance. A natural extension is to allow references between instance documents. A common example would be to have definitions in one instance document and to reference these definitions from other instance documents.

[Definition: JBind uses a so called data context to allow references between instance documents. On the one side a data context stores indexed data (i.e. data that has an ID attribute, a type key, or type unique constraint) and on the other side it stores open references (i.e. data with an IDREF/IDREFS attribute or with a type keyref constraint) while a data tree is validated. The same data context can be used to validate several instance documents thereby allowing references between instances.]

Note:

The current implementation of a data context is not thread safe.

In the example schema of section 3.4 Example Schema the MeansOfTransport type is defined to have a manufacturer attribute of type IDREF. The Manufacturer has a corresponding attribute of type ID. We deal with this situation by first reading a file that contains manufacturers and then a file containing means of transports. An example consisting of 2 XML files and a snippet of Java Code that reads and processes them is shown below.

ManufacturersMeans of Transports
<?xml version="1.0" encoding="UTF-8" ?>
<manufacturers
  xmlns:xsi=
    "http://www.w3.org/2001/XMLSchema-instance"
  xmlns="meansOfTransport"
  xsi:schemaLocation=
    "meansOfTransport meansOfTransport.xsd">
  <manufacturer id="manuId1"
    name="Daymler-Chrysler"/>
  <manufacturer id="manuId2" name="Volvo"/>
</manufacturers>
<?xml version="1.0" encoding="UTF-8" ?>
<meansOfTransports
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="meansOfTransport"
  xsi:schemaLocation="meansOfTransport meansOfTransport.xsd">
  <truck manufacturer="manuId1" numberOfWheels="8"
    fuelType="benzin" consumptionInLitres="25.0"
    loadCapacityInTons="30.0">
    <engine/>
  </truck>
  <vehicle xsi:type="Truck" manufacturer="manuId2"
    numberOfWheels="4" fuelType="super"
    consumptionInLitres="5.0" loadCapacityInTons="5.0">
    <engine/>
  </vehicle>
</meansOfTransports>
Java Code
package org.jbind.example.meansOfTransport;

import org.jbind.xml.core.data.IDataContext;
import org.jbind.xml.instance.builder.DataContext;
import org.jbind.xml.facade.JBindFacade;
import org.jbind.xml.msg.XmlException;
import java.util.Iterator;

public class Main {
  public static void main(String[] args) {
    // Create a shared data context
    IDataContext context = new DataContext(true);
    try {
      // Read manufacturers
      JBindFacade.unmarshal(Main.class.getResource("manufacturers.xml"), context);
      // Read means of transports
      IMeansOfTransportsData data = (IMeansOfTransportsData)
      JBindFacade.unmarshal(Main.class.getResource("meansOfTransports.xml"), context);
      for (Iterator i = data.iterMeansOfTransports(); i.hasNext(); ) {
        IMeansOfTransport mot = (IMeansOfTransport)i.next();
        IManufacturerData man = mot.refManufacturer();
        System.out.println("MeansOfTransport was manufactured by: " + man.getName());
      }
    } catch (XmlException e) {
      e.printStackTrace();
      System.exit(-1);
    }
    System.exit(0);
  }
}

6 XML Code

[Definition: The term XML Code is used to denote an instantiated data class structure that may posses some behaviour, i.e. some of the data classes may be derived from manually implemented behaviour classes.] In most cases XML code is the result of unmarshalling an instance document. JBind offers functionalities for common situations of XML code: configuration code and application code.

[Definition: XML Configuration Code is XML code where the root data class must implement the IConfiguration interface and where some of the contained data classes may implement the ISetupAndTearDown interface.] Configuration code is managed by the ConfigurationCode class that has functionalities to read in configuration data, to set it up, and to tear it down after usage. Configuration code can either be instantiated directly or by using the createConfigurationCode methods of the JBindFacade.

The setup and the tear down processes visit every data object in the XML configuration code and call the setup or tearDown method of each data object that implements the ISetupAndTearDown interface, respectively. Children are setup before their ancestors and ancestors are teared down before their children. These processes may have several levels, i.e. the structure is visited several times whereby a level counter is incremented during a setup process or decremented during a tear down process. This allows to handle situations where ancestors must be setup before their children or children must be teared down before their ancestors.

[Definition: XML Application Code is derived from XML configuration code by adding an execute method. Application code must implement the IApplication interface where the execute method is defined.] XML application code can be executed by using the JBindFacade or by using the main method of the ApplicationCode class:

java org.jbind.xml.code.ApplicationCode -url <applicationUrl>

6.1 "Hello World!"

The schema presented in section 5.2 Extensions is used as a base for an XML application. This is done be implementing the IApplication and the ISetupAndTearDown interfaces in the World and Person. behaviour classes, respectively. Note that the getNbSetupAndTearDownLevels method is realized by having a corresponding attribute in the World type. The two classes, an application instance document, and the output of the application are shown below.

WorldPerson
package org.jbind.example.helloWorld;

import org.jbind.xml.msg.XmlException;
import java.util.Iterator;

public abstract class World
  extends org.jbind.xml.instance.data.AnyTypeData
  implements IWorld {
  public int execute() {
    try {
      System.out.println("countries: " +
        numberCountries());
      System.out.println("total area: " +
        numberTotalArea());
      for (Iterator i = selectAllCountries();
        i.hasNext(); ) {
        ICountryData c = (ICountryData)i.next();
        System.out.println(c.stringCountrySummary());
      }
      for (Iterator i = selectAllPersons();
        i.hasNext(); ) {
        IPerson p = (IPerson)i.next();
        System.out.println(p.sayHello());
      }
    } catch (XmlException e) {
      e.printStackTrace();
      return -1;
    }
    return 0;
  }
}
package org.jbind.example.helloWorld;

public abstract class Person
extends org.jbind.xml.instance.data.AnyTypeData
implements IPerson {
  public String sayHello() {
    ICityData c = refCity();
    return "Hello World! I am " +
    getPersonName() + " from " + c.getCityName() + ".";
  }
  public void setup(int aLevel) {
    System.out.println("setup (" + aLevel + "): "
    + getPersonName());
  }
  public void tearDown(int aLevel) {
    System.out.println("tear down (" + aLevel + "): " 
    + getPersonName());
  }
}

XML Application (world.xml)Application Output (with 2 setup/tear down levels)
<?xml version="1.0" encoding="UTF-8" ?>
<world xmlns="helloWorld"
  nbSetupAndTearDownLevels="2"
  xsi:schemaLocation="helloWorld hello.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <country countryName="Germany"
    countryId="GER" area="357046">
    <city cityName="Berlin" cityId="BER"/>
    <city cityName="Karlsruhe" cityId="KA"/>
  </country>
  <country countryName="United States of America"
    countryId="USA" area="3717796">
    <city cityName="Washington DC" cityId="WAS"/>
  </country>
  <country countryName="United Kingdom"
    countryId="UK" area="244101">
    <city cityName="London" cityId="LON"/>
  </country>
  <country countryName="France"
    countryId="FR" area="543965">
    <city cityName="Paris" cityId="PAR"/>
  </country>
  <person personName="Gerhard Schröder"
    cityId="BER" countryId="GER"/>
  <person personName="George W. Bush"
    cityId="WAS" countryId="USA"/>
  <person personName="Tony Blair"
    cityId="LON" countryId="UK"/>
  <person personName="Jacques Chirac"
    cityId="PAR" countryId="FR"/>
</world>
setup (0): Gerhard Schröder
setup (0): George W. Bush
setup (0): Tony Blair
setup (0): Jacques Chirac
setup (1): Gerhard Schröder
setup (1): George W. Bush
setup (1): Tony Blair
setup (1): Jacques Chirac
countries: 4.0
total area: 4862908.0
country Germany has 2 cities.
country United States of America has 1 cities.
country United Kingdom has 1 cities.
country France has 1 cities.
Hello World! I am Gerhard Schröder from Berlin.
Hello World! I am George W. Bush from Washington DC.
Hello World! I am Tony Blair from London.
Hello World! I am Jacques Chirac from Paris.
tear down (1): Gerhard Schröder
tear down (1): George W. Bush
tear down (1): Tony Blair
tear down (1): Jacques Chirac
tear down (0): Gerhard Schröder
tear down (0): George W. Bush
tear down (0): Tony Blair
tear down (0): Jacques Chirac

6.2 BabelFish SOAP Client

A simple SOAP client for the AltaVista BabelFish service is implemented as another example of an XML application. This service is based on SOAP 1.1 (cf. [SOAP-1.1]).

In order to have JBind "talk" SOAP 1.1 some special steps have to be taken. The reason is that SOAP 1.1 is not based on [XSD-0] but on an intermediate working draft. Two schema documents xml-schema-1999.xsd and xml-schema-instance-1999.xsd are included that contain the definitions from these namespaces that are necessary to talk with the BabelFish service.

The soap11.xsd schema document contains the type Client whose attributes contain the information that is necessary to talk to a SOAP service. In addition, it has a behaviour class where the execute method of the XML application is implemented. The Client class contains only SOAP specific functionalities. It creates a SOAP envelope, validates the envelope, marshals the envelope for transmission, does the networking, and unmarshals the result. All service dependent parts are delegated to an envelopeHandler that must be configured as an element of the client. The following code snippet shows the corresponding lines from the Client class:

ISchema schema = Schemas.getInstance().getSchema("http://www.jbind.org/examples/soap11");
IFactoryData factory = (IFactoryData)schema.getFactory();
IEnvelopeData envelope = (IEnvelopeData)factory.createEnvelope();
getEnvelopeHandler().fillEnvelope(envelope);
JBindFacade.validateData(envelope, null);
URL url = new URL("http", getHost(), getPort(), getFile());
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml");
connection.setRequestProperty("SOAPAction", getAction());
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
JBindFacade.marshal(os, "UTF-8", true, envelope, null, null);
os.flush();
connection.connect();
InputStream is = connection.getInputStream();
InputSource inputSource = new InputSource(is);
IEnvelopeData result = (IEnvelopeData)JBindFacade.unmarshal(inputSource, null);
getEnvelopeHandler().acceptResult(result);
          

The BabelFish specific part includes a schema document with the defintions of the SOAP body blocks of the request/response messages and of the BabelFishEnvelopeHandler. In addition, the methods to fill a SOAP envelope with a corresponding request element and to accept the response have to be implemented. For brevity, only the definition of the soap client, the implementation of the BabelFishEnvelopeHandler, the XML application code, and the result of running the application is shown here:

SOAP Client and ResultBabelFish Envelope Handler
<complexType 
  name="Client" 
  jb:hasBehaviour="true">
  <sequence>
    <element 
      ref="tns:envelopeHandler"/>
  </sequence>
  <attribute name="host" 
    type="anyURI" 
    use="required"/>
  <attribute name="port"
    type="unsignedShort" 
    use="required"/>
  <attribute name="file" 
    type="string" 
    use="required"/>
  <attribute name="action" 
    type="string" 
    use="required"/>
</complexType>

<complexType 
  name="EnvelopeHandler"
  jb:hasBehaviour="true" 
  abstract="true"/>

<element 
  name="envelopeHandler"
  type="tns:EnvelopeHandler"/>
 
input : it's raining cats and dogs
output: es regnet Katzen und Hunde
package org.jbind.example.soap.babelFish;

import org.jbind.example.soap.soap11.IEnvelopeData;
import org.jbind.example.soap.soap11.IBodyData;
import org.jbind.xml.msg.XmlException;
import java.util.Iterator;
import org.jbind.base.Console;

public abstract class BabelFishEnvelopeHandler 
extends org.jbind.example.soap.soap11.EnvelopeHandler
implements IBabelFishEnvelopeHandler {
  
  public void fillEnvelope(IEnvelopeData anEnvelope)
  throws XmlException {
    IBodyData body = anEnvelope.createBody();
    IBabelFishData request = (IBabelFishData)body
    .createElement_("urn:xmethodsBabelFish","BabelFish",
    null, null);
    request.createTranslationmode(getTranslationMode());
    request.createSourcedata(getTextToTranslate());
  }
  
  public void doAcceptResult(IEnvelopeData anEnvelope) 
  throws XmlException {
    IBodyData body = anEnvelope.getBody();
    for (Iterator i = 
      body.iterElements_("urn:xmethodsBabelFish",
      "BabelFishResponse"); i.hasNext(); ) {
      IBabelFishResponseData response =
      (IBabelFishResponseData)i.next();
      Console.out("input : " + getTextToTranslate());
      Console.out("output: " + response.getReturn());
    }
  }
}
XML Application Code
<?xml version="1.0" encoding="UTF-8" ?>
<soap11:client
  xmlns:soap11="http://www.jbind.org/examples/soap11"
  xmlns:bf="urn:xmethodsBabelFish"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    urn:xmethodsBabelFish                     babelFish.xsd
    http://schemas.xmlsoap.org/soap/encoding/ ../soap11/soap-encoding.xsd
    http://schemas.xmlsoap.org/soap/envelope/ ../soap11/soap-envelope.xsd
    http://www.w3.org/1999/XMLSchema          ../soap11/xml-schema-1999.xsd
    http://www.w3.org/1999/XMLSchema-instance ../soap11/xml-schema-instance-1999.xsd
    http://www.jbind.org/examples/soap11      ../soap11/soap11.xsd"
  host="services.xmethods.net" port="80" file="/perl/soaplite.cgi" 
  action="urn:xmethodsBabelFish#BabelFish"
>
  <bf:envelopeHandler translationMode="en_de" textToTranslate="it's raining cats and dogs"/>
</soap11:client>

Note:

The schemaLocation attribute in the XML application code has the effect that all listed schema documents are loaded. If the schema documents would not be loaded by this mechanism then the location of the schema documents would have to be configured (cf. 7.8 How Instances are Linked with their Schemas).

6.3 Maze Game

The maze game is realized by a simple web application implemented mainly by the MazeServlet class. The maze structure is specified by a schema consisting of rooms and exits linking these rooms. The servlet is configured by a maze instance document and allows to "move" between the different rooms. The HTML view of a room is generated by a stylesheet using an XSLT processor. The room data (i.e. its name and exits) is supplied to the stylesheet by creating a SAXSource for the data.

Maze SchemaMaze Instance and XSLT-Template
<element name="maze" type="tns:Maze"/>

<complexType name="Maze" jb:hasBehaviour="true">
  <annotation>
    <appinfo>
      <jb:keyref name="initialRoom"
          refer="tns:roomIndex">
        <selector xpath="."/>
        <field xpath="@initialRoom"/>
      </jb:keyref>
    </appinfo>
  </annotation>
  <choice minOccurs="0" maxOccurs="unbounded">
    <element name="room" type="tns:Room"/>
  </choice>
  <attribute name="initialRoom" type="Name"/>
</complexType>

<complexType name="Room" jb:hasBehaviour="true">
  <annotation>
    <appinfo>
      <jb:key name="roomIndex"
          jb:referencedType="tns:Room">
        <selector xpath="."/>
        <field xpath="@name"/>
      </jb:key>
      <jb:unique name="x" scope="local">
        <selector xpath="exit"/>
        <field xpath="@name"/>
      </jb:unique>
    </appinfo>
  </annotation>
  <sequence>
    <element name="exit" type="tns:Exit" minOccurs="0"
      maxOccurs="unbounded"/>
  </sequence>
  <attribute name="name" type="Name" use="required"/>
</complexType>

<complexType name="Exit">
  <annotation>
    <appinfo>
      <jb:keyref name="toRoom" refer="tns:roomIndex">
        <selector xpath="."/>
        <field xpath="@toRoom"/>
      </jb:keyref>
    </appinfo>
  </annotation>
  <attribute name="name" type="Name"/>
  <attribute name="toRoom" type="Name"/>
</complexType>
<maze xmlns="maze"
   xsi:schemaLocation="maze maze.xsd"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   initialRoom="Room1">
  <room name="Room1">
    <exit name="east" toRoom="Room2"/>
    <exit name="south" toRoom="Room3"/>
  </room>
  <room name="Room2">
    <exit name="west" toRoom="Room1"/>
    <exit name="south" toRoom="Room4"/>
  </room>
  <room name="Room3">
    <exit name="north" toRoom="Room1"/>
  </room>
  <room name="Room4">
    <exit name="north" toRoom="Room2"/>
    <exit name="beam" toRoom="Room1"/>
  </room>
</maze>
 
<html xsl:version="1.0"  xmlns:x="maze"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="rName" select="x:room/@name"/>
  <head>
    <title>
      Maze - <xsl:value-of select="$rName"/>
    </title>
  </head>
  <body>
    <h2>
      You are in: <xsl:value-of select="$rName"/>
    </h2>
    <p>Where do you want to go?<p/>
    <p>
      <xsl:for-each select="x:room/x:exit">
        <a href="?room={$rName}&amp;exit={@name}">
          <xsl:value-of select="@name"/>
        </a><br/>
      </xsl:for-each>
    </p>
  </body>
</html>

Init Method of MazeServlet Process Request Method
// Read the maze configuration
String maze = aConfig.getInitParameter("maze");
URL url = getClass().getResource(maze);
myConfigurationCode =
  JBindFacade.createConfigurationCode(url, null);
myConfigurationCode.setup();
myMaze = (IMaze)myConfigurationCode.getCode();
// Read and prepare the XSL
String template = aConfig.getInitParameter("template");
url = getClass().getResource(template);
TransformerFactory transformerFactory =
  TransformerFactory.newInstance();
if (!transformerFactory.getFeature(SAXSource.FEATURE)) {
  throw new ServletException("SAXSource not supported");
}
Source xsl = new StreamSource(url.toString());
myStylesheet = transformerFactory.newTransformer(xsl);
// Determine the next room
IRoom nextRoom = null;
String roomName = aRequest.getParameter("room");
if (null == roomName) {
  nextRoom = myMaze.refInitialRoom();
} else {
  IRoom srcRoom = myMaze.getRoomByName(roomName);
  String exitName = aRequest.getParameter("exit");
  IExitData exit = srcRoom.getExitByName(exitName);
  nextRoom = exit.refToRoom();
}
// Generate the response
aResponse.setContentType("text/html");
PrintWriter out = aResponse.getWriter();
Source request = JBindFacade.createSaxSource(nextRoom);
Result response = new StreamResult(out);
try {
  myStylesheet.transform(request, response);
} catch (TransformerException e) {
  throw new ServletException(e);
}
out.close();

The JBind distribution contains the maze.war file that can directly be deployed in any servlet container. Using JBoss in its standard configuration it can be accessed under the URL http://localhost:8080/maze/.

7 JBind Configuration

JBind is configured using Java preferences that are managed by the Config class. This class offers possibilities to reset, import, export, and modifiy the preferences via the command line. See the JavaDoc of the Prefs class for a complete description of the command line interface. The default configuration of JBind can be viewed by first resetting the configuration and then exporting it into a file. The following command line performs this task:

java org.jbind.xml.Config -reset -export config.xml

The used preferences are configured by system properties[1]:

propertypossible valuesdefaultdescription
jBindPreferenceTree system, user user Determines if the system or the (current) user preference tree is used.
jBindInitConfig true, false true Determines if the configuration is initialized. If set to true the configuration is either reset to its default or a configuration resource is imported.
jBindConfig URL or filename Relevant only if the jBindInitConfig property is set to true. If the specified resource contains the substring "://" then it is used as a URL to access the configuration resource. Otherwise the getResourceAsStream method of Config.class used to access the resource.

7.1 Validation Options

switchpossible valuesdefaultdescription
strictSchemaValidation true, false false JBind allows arbitrary particles to occur inside "all" model groups. If set to true then only element declarations with a maxOccurs of 1 are allowed.
checkLanguageCode true, false false Determines if the language code in language data objects is checked. The known language codes are stored in the files languages-2.txt and languages-3.txt.
checkCountryCode true, false false Determines if the country code in language data objects is checked. The known country codes are stored in the file countries.txt.

7.2 ClassLoader Configuration

JBind uses the class loader that loaded JBind or the context ClassLoader to load the classes during instantiating instance documents. It can be configured if the JBind class loader is tried first and then the context class loader or vice versa.

7.3 Regular Expressions

The name of a class can be configured that is used to create regular expression. The configured class must implement the IRegExFactory interface.

7.4 XPath

The name of a class can be configured that is used to create XPaths. The configured class must implement the IXPathFactory interface. The used XPath factory is related to the data implementation factory because (normally) XPaths are evaluated base on the data implementation.

7.5 Data Implementation Factory

The name of a class can be configured that is used to create data implementations. The configured class must implement the IDataImplFactory interface. The used data implementation factory is related to the used XPath factory (see above).

7.6 Namespace to Package Mapping

A mapping from namespaces to package names can be configured. This mapping is used to define the schema package of schemas for which no other package information is available. For the precedence of package information see 3.3 Parameterizing the Code Generation.

7.7 Entity Resolver, Import, and Include

The name of the class can be configured that is used to resolve entities for SAX parsers. The configured class must implement the org.xml.sax.EntityResolver interface.

In many cases the default mechanism used by JBind is sufficient. [Definition: Entities are resolved with the help of XML catalogs (cf. [XML Catalogs]). In short, XML catalogs can resolve entities given their public or system identifiers and they can map URIs into URIs.] JBind uses XML catalogs to resolve entities during SAX parsing and to map namespace URIs into schema document URLs.

The keys of the xmlCatalogs node in the configuration specify the XML catalogs to be used. The value a key maps into specifies how a catalog is loaded. Two modes are supported: 1. Catalogs might be accessed by a class loader using the Config.class.getResource method (LOAD_BY_CLASS_LOADER) or 2. by URLs (LOAD_BY_URL). Relative URLs are resolved relative to the current user home directory. In the default configuration JBind tries to load the following catalogs:

LocationLoad Modedescription
/org/jbind/catalog.xmlclass loaderJBind catalog (for internal use)
/catalog.xmlclass loaderapplication catalog (for free use by applications)
.catalog.xmlURLuser catalog (for free use by user)

The standard configuration of JBind allows the integration of arbitrary XML catalogs very easily because of the predefined application and user catalog. In order to have an XML catalog used by JBind simply name it "catalog.xml" and make it accessible to the class loader or name it ".catalog.xml" and place in the user home directory.

When a namespace is imported by an import element then the location of the schema document for the namespace is determined by trying several options in sequence. The algorithm first determines a resulting URL and then an effective URL that is finally used to access the schema document. The options are:

  1. If the namespace URI is mapped into a URL by an XML catalog entry then this URL is used as the resulting URL.

  2. If the import element has a schemaLocation attribute then this URL is used as the resulting URL.

  3. Otherwise the namespace URI is used as the resulting URL.

It is tried to map the resulting URL once again using the XML catalog yielding the effective URL. If there is no entry for the resulting URL in the XML catalog then the resulting URL is used as the effective URL.

The situation, when a schema document of a namespace is introduced in an instance document using the xsi:schemaLocation or xsi:noNamespaceSchemaLocation attribute is treated similarly to importing namespaces:

  1. If the namespace URI is mapped into a URL by an XML catalog entry then this URL is used as the resulting URL.

  2. Otherwise the specified URL is used as the resulting URL.

As above, the resulting URL is either directly used as the effective URL or mapped once again using the XML catalog.

When a schema document is included or redefined by an include or redefine element, respectively, then it is also tried to map the URL specified by the schemaLocation attribute using the XML catalog.

Note:

JBind uses the XML catalogs implementation of Norman Walsh (cf. A Installation) that has additional configuration possibilities. For details refer to the documentation of that package.

7.8 How Instances are Linked with their Schemas

When an instance document is unmarshalled then the corresponding schema information must be available. JBind offers several possiblities to link instance documents with their schemas.

  1. By using the xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes in instance documents.

    This situation is described in section 7.7 Entity Resolver, Import, and Include. In short, the URL of a schema is either looked up in an XML catalog based on either its namespace or the specified URL. If the lookup does not return a URL then the specified URL is used.

  2. By explictly reading in and registering schemas before instance documents refer to them.

    While an instance document is unmarshalled JBind looks up schema information for every globally scoped element or attribute using the Schemas singleton. A schema can be read in by the JBindFacade.readSchema method and registered by the Schemas.setSchema method.

A Installation

JBind is developed for Java 1.4. However, it is possible to use JBind with Java 1.3 after a few obvious modifications.

JBind uses an external library for its XPath functionality. The used library can be configured (cf. 7 JBind Configuration). In its default configuration JBind uses the Jaxen XPath engine. For the XML catalogs mechanism source code of Norman Walsh was copied and slightly extended to cope with catalogs that are contained in JARs. The original source is available at http://wwws.sun.com/software/xml/developers/resolver/. In addition, JBind contains a copy of the regular expression engine used in Xerces.

In order to build JBind the following libraries must be available:

The distribution of JBind contains a ready to use jBind.jar archive. In order to build the JBind archive and to run the examples the listed jars must be placed in the jBind/lib directory. It is possible to place the JavaCC library in the jBind/tool directory because JavaCC is used during the build process only and never during runtime. An archive containing all necessary libraries is available at http://sourceforge.net/projects/jbind/.

B Glossary

The listing contains all the definitions which appear in the document above.

behaviour class
Behaviour classes that inherit from the behaviour classes of their base types and from the corresponding behaviour interfaces. Behaviour classes are abstract classes where the additional methods declared in the behaviour interfaces are (manually) implemented. They are abstract because the methods declared in the data interfaces are not implemented here. Behaviour classes are generated only once by the code generator and will never be overwritten.
behaviour interface
Behaviour interfaces that are derived from the corresponding data interfaces and contain declarations of manually added methods. Behaviour interfaces are generated only once by the code generator and will never be overwritten.
binding attribute
A binding attribute is an attribute that belongs to the JBind namespace.
Bound Schema
A bound schema is the result of applying binding information contained in a schema adjunct document to a schema document.
cartridge
A cartridge can be plugged into the schema compiler and is responsible for generating a certain kind of source.
data class
Data classes that inherit from the corresponding behaviour classes and that normally implement the accessor methods defined in the corresponding data interfaces. A data class is abstract if its type in the schema is defined to be abstract. In this case no accessor methods are generated. Yet, the data class is generated if it contains static inner classes for its anonymous inner types. Data classes must not be edited manually because they are overwritten by the code generator.
data context
JBind uses a so called data context to allow references between instance documents. On the one side a data context stores indexed data (i.e. data that has an ID attribute, a type key, or type unique constraint) and on the other side it stores open references (i.e. data with an IDREF/IDREFS attribute or with a type keyref constraint) while a data tree is validated. The same data context can be used to validate several instance documents thereby allowing references between instances.
data implementation
The implementation is called the data implementation
data interface
Data interfaces that contain declarations of accessor methods for the attributes and elements of a type, declarations of methods to access referenced data, and declarations of methods that are based on XPaths. In addition, if an enumeration constraint is imposed on a type then corresponding constants are generated. Data interfaces must not be edited manually because they are overwritten by the code generator.
defaulted binding attribute
defaulted binding attributes that take their default value from the schema element they are nested in. If a schema is included by another schema then the including schema is also considered.
extension element
An extension element is an element in the JBind namespace that appears inside an appinfo element
global constraint
After manipulation the global constraints can be checked by calling the validateData method of the JBindFacade. Global constraints consider XML data as a whole. They contain identity constraints, occurence constraints, and XPath constraints.
JBind namespace
Let the JBind namespace be "http://www.jbind.org"
local binding attribute
Some binding attributes have an effect only on the tag at which they appear. They are called local binding attributes.
local constraint
During manipulation only local constraints are enforced, i.e. constraint that consider only the simple content of elements or attributes. Amongst these constraints are the inherent constraints of simple types, constraints based on facets, and fixed values.
propagating binding attribute
Other binding attributes are propagated along nested tags. They are called propagating binding attributes.
property name
Each property has a property name. In case of an element/attribute declaration the property name is equal to the name of the declaration. In case of a reference constraint the name is either equal to the name if the referencing attribute or to the name of the reference constraint. Property names may be overloaded by the name binding attribute.
schema adjunct document
Schema adjunct documents are used by JBind to store binding information for schema documents in separate documents.
schema factory
The schema factory of a schema is used to instantiate top-level data classes.
schema package
All classes/interfaces that are generated for a schema are placed into a common package that is called the schema package
simple storage type
Data types that are derived from anySimpleType have a simple storage type. This is the type used to store values of the corresponding type. Simple storage types are either primitive types (like int or double) or they are (simple) reference types (like String or BigDecimal).
simple storage value
Each storage class whose type is derived from anySimpleType has a simple storage value. A simple storage value is for example an int or a String.
storage class/interface
Classes/interfaces that are responsible for the storage of values are called storage classes/interfaces
storage hierarchy
Corresponding to the datatype hierarchy there is a hierarchy of these classes/interfaces that is called the storage hierarchy
type property
Accessor methods are based on the properties of a type, i.e. on its attribute/element declarations and on its reference constraints
XML application code
XML Application Code is derived from XML configuration code by adding an execute method. Application code must implement the IApplication interface where the execute method is defined.
XML catalogs
Entities are resolved with the help of XML catalogs (cf. [XML Catalogs]). In short, XML catalogs can resolve entities given their public or system identifiers and they can map URIs into URIs.
XML code
The term XML Code is used to denote an instantiated data class structure that may posses some behaviour, i.e. some of the data classes may be derived from manually implemented behaviour classes.
XML configuration code
XML Configuration Code is XML code where the root data class must implement the IConfiguration interface and where some of the contained data classes may implement the ISetupAndTearDown interface.

C References

DOM
DOM: Document Object Model. (See http://www.w3.org/DOM/.)
Generative Programming
Czarnecki & Eisenecker. Generative Programming. Methods Tools, and Applications. Addison Wesley 2000.
GOF
E. Gamma et al. Design Patterns. Elements of Reusable Object-Oriented Software. Addison Wesley 1995.
Namespace 1.1
Namespaces in XML 1.1. (See http://www.w3.org/TR/xml-names11/.)
Schematron
Schematron. An assertion language for XML. (See http://sourceforge.net/projects/schematron.)
SOAP-1.1
Simple Object Access Protocol (SOAP) 1.1. (See http://www.w3.org/TR/SOAP/.)
XInclude
XML Inclusions (XInclude) Version 1.0. (See http://www.w3.org/TR/xinclude/.)
XML Catalogs
XML Catalogs. (See http://www.oasis-open.org/committees/entity/spec.html.)
XSD-0
XML Schema Part 0: Primer. (See http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/structures.html.)
XSD-1
XML Schema Part 1: Structures. (See http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/structures.html.)
XSD-2
XML Schema Part2: Datatypes. (See http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/datatypes.html.)

D Acknowledgements

This document was produced with the help of the XML Document Production Tools of the W3C. In particular, a slightly modified version of xmlspec-v21.dtd and an adapted xmlspec.xsl was used.


End Notes

[1]

System properties are specified on the command line with "-D" arguments.