The XMLBuilder

 

Although packaged with the Send Fax library, the XMLBuilder is a standalone tool used to converts a java beans graph (the model) into an xml document.

The builder exposes two basic methods: one to map the model to an xml document (a DOM tree) and the other to save the xml document.

Usage:

   // Step 1:  create document (DOM tree)

      XMLBuilder builder = new  XMLBuilder();

 

      /* Namespace handling defaults to false.

         If true, the meta-document must declare the namespace URI http://xml.utility/XMLBuilder

         on its root element and all meta-attributes must be qualified.

         Example: <root xmlns="http://fax.server.com/" xmlns:xmb="http://xml.utility/XMLBuilder">

                       <child xmb:property="..." .../>

                       . . .

                  </root>

      */       

      builder.setNameSpaceAware(true); 

 

      File f = new File(metatDocPath); 

      FileInputStream fis = new FileInputStream(f);         

      Document doc = builder.createDocument(faxModel, fis);

 

   // Step 2: save document

      Properties props = new Properties();

      props.put(OutputKeys.METHOD, "xml");

      props.put(OutputKeys.ENCODING, "ISO-8859-1");

      props.put(OutputKeys.INDENT, "yes");

      f = new File(docPath);

      builder.saveDocument(doc, new FileOutputStream(f), props);

 

 

Mapping java beans to xml document:

To create the DOM tree from the model, the XMLBuilder uses a meta-document (e.g. GatewayMetaDoc).  The meta-document is an XML skeleton of the document to be produced by the XMLBuilder.  Meta-document elements may have meta-attributes the XML builder uses to produce the DOM tree.

The meta-attributes supported are specified by the processing instruction: <?meta-att-list value="property index childIsText skip default"?>

 

 

Definitions

 

The property meta-attribute:

When parsing the meta-document, this attribute instructs the builder to map the current element with a property from the model.

In the following example, the builder will map the recipient-list element with the model property: recipientList.

 

<recipient-list property="recipientList">

 

In this example, the property recipientList must be a first-level child of the model.

 

To map a model property that is not a first level child, the property name must be nested, as in:

 

<first-name property="senderInfo.firstName" childIsText="true"/>

 

In the above example, the builder will map the element first-name with the property firstName of the senderInfo bean.

Although not fully tested, the builder should support any other property name format described in the PropertyUtilsBean class, with a little variation for indexed property name.

 

Remarks:

 

Mapping a model list to a DOM node list (using the index meta-attribute):

To map a model list to a DOM node list, the builder expects a corresponding meta-document list element with only one occurrence, which will be used as a skeleton for the list content to be produced.

 

<recipient-list property="recipientList">

 <Recipient>

   <fax property="recipientList[{0}].faxNumber" index="0" childIsText="true"/>

   <title property="recipientList[{0}].title" index="0" childIsText="true" skip="true"/>            

   <first-name property="recipientList[{0}].name" index="0" childIsText="true"/>

   <company property="recipientList[{0}].company" index="0" childIsText="true"/>

 </Recipient>

</recipient-list>

 

In the above example, the recipient-list element is mapped to the model property: recipientList. 

When parsing this element, the builder determines the model property is in fact a java.util.List and expects the element to have only one child: (the <Recipient> element).  The builder will create a <Recipient> element for each entry of recipientList.

The recipient element children are mapped to the recipientList entries using the indexed and nested property name format:  recipientList[{0}].propertyName. The list index must be {0} (not [0]), because the builder uses the MessageFormat api, to replace {0} with the current value of the index meta-attribute. In a meta-document, the index attribute value must always be set to zero. The builder increments the value of the index attribute when iterating over a model list property.

 

Remarks:

 

The childIsText meta-attribute:

When an element has this meta-attribute, the builder creates a child text node for the element.  The text node value is the model property value.

 

Example:

If the model property senderInfo.firstName is “Bob”, the builder will produce the element: <first-name>Bob</first-name> when parsing the meta-document element: <first-name property="senderInfo.firstName" childIsText="true"/>. It should be noted that setting childIsText to false would produce the empty element: <first-name/>. 

 

Remarks:

 

The skip meta-attribute:

When the builder parses a meta-document element that has this attribute set to true, it will not create a node for that element.

 

Example:

Because the attribute skip is set to true, the title element will not be render in the output document.

<title property="recipientList[{0}].title" index="0" childIsText="true" skip="true"/>

 

Remarks:

 

The default meta-attribute:

This meta-attribute can be set on a meta-document element that is mandatory in the document to be created and for which the model has no corresponding property.

 

Remarks:

 

Mixing the meta-attributes (and the outcome of)

The user is responsible to properly combined meta-attributes and to apply them where it makes sense (terminal vs. non-terminal elements).   Otherwise, the document produced by the builder could be invalid according to its dtd or schema. The builder does not attempt to validate the mixtures or the meta-document.

 

The following table summarizes what the builder expects as mixtures and on which element (terminal or non-terminal) they could be applied.

 

Mixture

Outcome

1.

<element>

The builder adds the node <element> to the DOM tree.

2.

<element skip=”true”>
    <child property=”…”/>
</element>

The builder ignores the element (and its children)

3.

<element skip=”false”>
    <child property=”…”/>
</element>

The builder adds the node <element> to the DOM tree.

4.

<element default=”abc”/>

The builder adds the nodes <element>abc</element> to the DOM tree.

5.

<element property=”prop”>
    <child property=”…”/>
</element>

If the builder is unable to retrieve prop from the model for any reasons, it will throw an exception and stop parsing the meta-document.

if prop is null or is an empty list, the builder skips <element> and its children nodes. Otherwise, the builder adds the node <element> to the DOM tree.

6.

<element property=”prop” childIsText=”true”/>

If the builder is unable to retrieve prop from the model for any reasons, it will throw an exception and stop parsing the meta-document.

 

if prop is null or is an empty list, the builder skips <element>. Otherwise it invokes the toString() method on prop and adds the nodes <element>prop.toString()</element> to the DOM tree.

7.

<element property=”prop” childIsText=”false”/>

If the builder is unable to retrieve prop from the model for any reasons, it will throw an exception and stop parsing the meta-document.

 

if prop is null, the builder skips <element>.  Otherwise,  the builder adds the nodes <element/> to the DOM tree.

8.

<element property=”prop” childIsText=”true” skip=”true”/>

If the builder is unable to retrieve prop from the model for any reasons or prop is null, the builder will skip <element>.

Otherwise, the builder adds the node <element>prop.toString()</element> to the DOM tree.

9.

<element property=”prop” childIsText=”true” skip=”false”/>

<element property=”prop” childIsText=”false” skip=”false”/>

See 6.

 

See 7.

10.

<element property=”list[{0}].prop”  index=”0” childIsText=”true”/>

If the builder is unable to retrieve list[index].prop from the model for any reasons, it will throw an exception and stop parsing the meta-document.

 

if  list[index].prop is null, the builder skips <element>.  Otherwise, 

the builder adds the nodes <element>list[index].prop.toString()</element> to the DOM tree.

11.

<element property=”list[{0}].prop”  index=”0” childIsText=”false”/>

See 7.

12.

<element property=”list[{0}].prop”  index=”0” childIsText=”true” skip=”false”/>

<element property=”list[{0}].prop”  index=”0” childIsText=”true” skip=”true”/>

See 10.

 

See 8.

13.

<element property=”prop” skip=”true”>

    <child>…

</element>

If the builder is unable to retrieve prop from the model for any reasons, or prop is null or is an empty list, the builder will skip <element> and its children.

Otherwise, the builder adds the node <element> to the DOM tree.

14.

<element property=”prop” skip=”false”>

    <child>…

</element>

See 5.

15.

<element property=”prop”/>

If the builder is unable to retrieve prop from the model for any reasons, it will throw an exception and stop parsing the meta-document.

 

if prop is null, the builder will skip <element>. Otherwise, the builder adds the node <element> to the DOM tree.

16.

<element property=”prop” skip=”true”/>

If the builder is unable to retrieve prop from the model for any reasons or prop is null, the builder will skip <element>. Otherwise, the builder adds the node <element> to the DOM tree.

17.

<element property=”prop” skip=”false”/>

See 15.

18.

<element property=”prop” default=”abc”/>

If the builder is unable to retrieve prop from the model for any reasons or prop is null, the builder will add the nodes <element>abc</element> to the DOM tree.

19.

<element property=”prop” childIsText=”true” default=”abc”/>

If the builder is unable to retrieve prop from the model for any reasons or prop is null, the builder will add the nodes <element>abc</element> to the DOM tree. Otherwise, the builder adds the node <element>prop.toString()</element> to the DOM tree.

20.

<element property=”prop” childIsText=”false” default=”abc”/>

If the builder is unable to retrieve prop from the model for any reasons or prop is null, the builder will add the nodes <element>abc</element> to the DOM tree. Otherwise, the builder adds the node <element/> to the DOM tree.

 

 

Installing the builder:

 

The XMLbuilder tool has been developed and tested with JDK 1.4.2_05

The following libraries are needed in your CLASSPATH:

org.apache.common.beanutils     1.6.1
org.apache.common.collections  2.1.1
org.apache.common.logging       1.0.4

The builder has not been tested with lower or higher version of these librairies.

 

 

Javadoc:

The XMLBuilder javadoc is available here.