Examplotron Beans Tutorial

An Easy Way to XML-Java Data Binding

Tomáš Pitner

$Id: manual.xml,v 0.7 2003/03/31 23:00:00 tomp Exp $


Table of Contents

My first EGB schema
The structure of the generated class
The generated properties
The properties for attributes
The properties for child text nodes
The properties for child elements
Options for Generation
The EGB Interpretation of Examplotron constructs
The EGB examples
The EGB distribution

My first EGB schema

EGB is an extension to Examplotron, so almost any Examplotron-compliant schema is a EGB schema as well. Similarly, almost any well-formed XML document can act as an EGB schema. So, let's try to write a simple EGB schema:

  1. At first, suppose we have following document, simplest.xml.

    
    <?xml version="1.0"?>
    <book>My first EGB schema</book>
    
    

  2. Apply EGB compiler to the file: saxon7 -o simplest-eg.xml simplest.xml

  3. This will create java directory with package directory book containing one generated Java source file - Book.java

The default behavior of EGB is (assuming the prefix egb is properly mapped to the EGB namespace URI - http://examplotron.org/beans/):

  1. For each element (with some exceptions), generate a Java class. The name of the class is, by default, the same as the element local name with first letter uppercased. You can alter the class name by specifying egb:class attribute in the schema element.

  2. The created class source files are, by default, placed in package with the same name as the local name of the schema root element. You can, again, change the package name by specifying egb:package attribute in the appropriate schema element. If egb:package="", then the class is placed in the implicit package (i.e. no package declaration).

  3. All the generated Java packages are rooted, by default, in the java subdirectory. You can change it when calling the EGB compilation - pass the parameter javasrcdir to the transformation to override the default placement: saxon7 -o simplest-eg.xml simplest.xml javasrcdir=src will save the generated code to src.

  4. For the document, one class named RootElementClassNameDocument will be created. This class is the entry point for marshalling/unmarshalling of the object structure corresponding to the schema. The name of this root class can be modified by egb:document-class attribute in the schema root element.

  5. As a by-products of the generation, EGB will filter all EGB-specific constructs and thus produce an Examplotron schema roughly corresponding to the original EGB schema. In most cases, the document prescribed by the generated Examplotron schema will be also valid again EGB schema and can be unmarshalled by the generated classes. It can, thus, be used for validation of the document passed to unmarshalling. The produced Examplotron schema is sent to the standard output. The EGB examples show how to save the filtered schema to file.

The structure of the generated class

The structure of the generated class is simple; it consists of the following sections:

  1. The source file header contains package and import declarations (package can be implicit - in this case no package is declared.

  2. Section for constructors (not always generated).

  3. Section for properties corresponding to attributes of the source element.

  4. Section for properties corresponding to child elements of the source element.

  5. Section for properties corresponding to child text nodes of the source element.

  6. Section for methods related to unmarshalling/marshalling of the element/object.

The generated properties

The properties can be either single or multiple.

  1. Single property is represented directly as member variable of the appropriate type with set/get accessor methods.

  2. Multiple properties (that can occur multiple time) are represented as List member variable of the appropriate type with add/get list/get count/indexed get accessor methods.

The following examples are produced from this EGB source schema:


<item created="9999-99-99" price="1.2" count="10" id="ID" >
	<title>Titul zbozi</title>
	textovy popis zbozi
	<subitem count="9" >
		<title>titulek subitem</title>
	</subitem>
</item>

The properties for attributes

Suppose the source element had attribute price and its appropriate Java type was estimated to be float. Then the code for the property will be:

  1. 
    	// properties for ATTRIBUTES
    
    	// for attribute 'price'
    	// single property 'price' of type float
        private float price = 1.2f;
        public void setPrice(String aPrice) { setPrice(Float.parseFloat(aPrice)); }
        public void setPrice(float aPrice) { price = aPrice; }
        public float getPrice() { return price; }
    
    

  2. So, for each property, the member variable (price) and the accessor methods are created. The set method exists (for non-String properties) twice - the second accepting String (void setPrice(String aPrice)), initializing the property with a string value interpreted as float.

The properties for child text nodes

The child text nodes are represented with property named 'content'.

  1. 
    	// properties for TEXT nodes
    	// single property 'content' of type String
        private String content = "textual description of the item";
        public void setContent(String aContent) { content = aContent; }
        public String getContent() { return content; }
    
    

The properties for child elements

The child elements can be interpreted

  1. in the same manner as attributes - iff the child element contain ONLY one text node, nothing else - no child elements, no attributes. The type of the property is then either primitive or String:

    
    	// properties for child ELEMENTS
    
    	// for text()-only element 'title'
    	// single property 'title' of type String
        private String title = "Title of the goods item";
        public void setTitle(String aTitle) { title = aTitle; }
        public String getTitle() { return title; }
    
    

  2. otherwise - as member variables with the type of one of the generated class. The name of the property can is either equals to the element local name or can be changed by egb:name attribute.

    
    	// single property 'subitem' of type Subitem
        private Subitem subitem;
        public void setSubitem(Subitem aSubitem) { subitem = aSubitem; }
        public Subitem getSubitem() { return subitem; }
    
    

  3. The EGB serialization runtime is able to resolve and set also the non-primitive property values from the unmarshalled XML document.

Options for Generation

The generation of the class source files can be regulated by the following options:

  • package declarations - if egb:package attribute is present in an element, the generated class will be stored in package specified in the package attribute - for example, egb:package="com.foo" will assign the generated classed to package com.foo.

  • import declarations - if egb:import attribute is present in an element, the generated class will import packages and/or classes specified in the import attribute. Multiple values can be separated by comma - for example, egb:import="java.net.URL, java.io.*" will import class URL and all symbols from package java.io.

  • implements declarations - if egb:implements attribute is present in an element, the interface referenced by the attribute is implemented by the class created from the current element.

  • if egb:all-implement attribute is present in an element, the implemented interfaces are implemented by all classes created from the current element and all descendant elements. However, the egb:implements, if present, will suppress the declaration given in egb:all-implement.

  • extends declarations - if egb:extends attribute is present in an element, the generated class will extend the class specified in the extends attribute. For example, the element with attribute egb:extends="com.foo.Bar" will extend class com.foo.Bar.

  • if egb:all-extend attribute is present in an element, all classes created from the current element and all descendant elements extend the class specified in egb:all-extend. However, the egb:extends, if present, will suppress the declaration given in egb:all-extend.

The EGB Interpretation of Examplotron constructs

The generation of the class source files can be regulated by the following options:

  • eg:define="named_type" - eg:content="named_type" - the type of a property can be defined in another element. You can refer to the definition by eg:content="named_type". This construct can be seen in the first addressbook example.

  • eg:occurs="cardinality" declaration - cardinality can be ?, ., *, +. Then, the property must occurs 0..1 times, exactly once, any number of occurences, at least once, respectively. For further information, see the Examplotron and Relax NG documentation. Note, that both eg:content="named_type" and eg:occurs="cardinality" declarations can occur simultaneously.

  • eg:attribute name="att_name" ns="att_ns" declaration will create property as if it were specified as attribute of the element. The eg:attribute declaration enables to specify the type of the property via eg:content name="named_type". For further information, see the Examplotron documentation. With eg:attribute name="att_name" ns="att_ns", also the namespace of the attribute can be specified.

  • You can use all Examplotron "iconic datatypes". The EGB examples present some of them. However, since EGB is XML-Java data binding system, you can also use type specification in form of {java:type} (beside the Examplotron {xsd:type} or {dtd:type} type library). Warning: Using non-Examplotron types will cause incompatibility of the EGB schema with Examplotron.

The EGB examples

The examples are organized as follows (shown on the addressbook example):

  • addressbook.xml - EGB schema. The only source.

  • addressbook-eg.xml - Examplotron schema generated from EGB schema.

  • addressbook-dataX.xml - XML data to be fed into classes generated from addressbook.xml EGB schema.

to run the examples, perform the following steps [1]:

  1. Assuming you are in the EGB installation directory, e.g. /devel/egb.

  2. Change to examples subdirectory - current directory is now /devel/egb/examples.

  3. Run the compile batch with one argument - the name of the example. The names correspond to the names of the .xml files in the directory. Suppose we compile example addressbook as follows: compile addressbook.

  4. This will create directory java/addressbook, containing .java source files.

  5. Change to directory java and enter run addressbook (optionaly followed by an integer).

  6. This will compile the generated classes, run the Main class (written by user, not generated). This class' main method will unmarshall the data in addressbook-dataX.xml file (if integer X is omitted, addressbook-data.xml is processed.

  7. Beside of the creation of .java files, also an Examplotron schema will be created from the exmaple source. The Examplotron schema is stored (in case of addressbook example) in addressbook-eg.xml.

The EGB distribution

For more information about download, see manual.

The crucial files:

  • compile-beans.xsl - EGB compiler. Generates classes and filtered Examplotron schema.

  • tomp.xml.egb.Util - Utility class needed only in the generation phase.

  • tomp.xml.egb.EgbElement - Interface needed while compiling generated classes and while running unmarshalling/marshalling.

  • tomp.xml.egb.EgbContent - Interface needed while compiling generated classes and while running unmarshalling/marshalling.



[1] Note, however, that in the EGB distribution, the examples are already compiled and the resulting generated classes stored in their appropriate package directories under java. So, running the examples, as stated below, will cause overwritting of the existing example results.