prev table of contents next

4.2 Assembling Document Tree Nodes

Neither the methods of the element object factory nor the constructors of the classes derived from the types defined in the XML schema require that you have any of an element's child elements or attributes at the time of the call. (The single exception is the set of factory methods creating a JAXBElement<?>, but their arguments may be "empty" element objects, without any actual XML content.) This gives you maximum freedom to design your tree-building algorithm. Usually it will be the structure of the input material that advocates some specific approach. Building the document tree from comparable hierarchical structures is the easiest way, as you can create, insert and fill the elements as you traverse the existing structure. Sequential orderings that correspond to one of the basic tree traversal orders can be handled with elementary techniques. If, for instance, the data is in post-order, you might use a stack to keep assembled XML elements until their parent element becomes eligible for construction. If the data isn't arranged in one of the tree traversal orders you could set up two or more "cursors" that point into the emerging tree so that you might add to several places in parallel.

The frequently used construction method that proceeds from the tree root towards the leaves may be written according to two typical scenarios for the construction of an element. We'll illustrate these with a skeleton layout for a product order.

<xsd:complexType name="CustomerType">
  <xsd:sequence>
    <xsd:element name="id"   type="xsd:int"/>
    <xsd:element name="name" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ItemType">
  <xsd:sequence>
    <xsd:element name="id"       type="xsd:string"/>
    <xsd:element name="quantity" type="xsd:int"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="OrderType">
  <xsd:sequence>
    <xsd:element name="customer" type="CustomerType"/>
    <xsd:element name="items"    type="ItemType" maxOccurs="unbounded"/>
  </xsd:sequence>
</xsd:complexType>

<xsd:element name="folder">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element name="orders"   type="OrderType" maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>
Assuming that we are about to add the content for a "current" element, the sequence for adding a solitary subordinate element of type X goes like this:
  1. Create the subordinate element xElem via a call to factory method createX.
  2. Add this object to the current element, with a setter call current.setX( xElem ).
  3. Make the new element the current element and repeat this process recursively for the new element's offsprings.
This is, of course, simply to be repeated for other child elements. If the subordinate element occurs repeatedly, we extend this algorithmic outline somewhat:
  1. Create the subordinate element xElem via a call to factory method createX.
  2. Obtain the reference to the subordinate List<X>, with a call to the getter current.getX().
  3. For each subordinate element:
    1. Create it using the factory method createX.
    2. Append (add) it to the List<X>.
    3. Make the new element the current element and repeat this process recursively for the new element's offsprings.
It may be a good strategy to insert a newly created element immediately after its creation. It reduces the risk that this essential operation is left out.

You should now have no problems understanding the Java code that creates an order element according to the previously given schema snippet.

// Data for an order
int custId = ...;
String custName = ...;
Item[] items = ...;

// Create order and insert in top-level document, a list of orders
OrderType orderElem = objFact.createOrderType();
folder.getOrders().add( orderElem );

// Create and insert the customer element.
CustomerType custElem = objFact.createCustomerType();
orderElem.setCustomer( custElem );
// Complete customer.
custElem.setId( custId );
custElem.setName( custName );

// Create and add item elements.
List<ItemType> itemList = orderElem.getItems();
for( Item item: items ){
    ItemType itemElem = objFact.createItemType();
    itemList.add( itemElem );
    itemElem.setId( item.id );
    itemElem.setQuantity( item.qtty );
}
Another thing that can be gleaned from these lines is the danger of confusion. On the one hand, we have the classes representing XML elements, and, on the other hand, the data for the XML document is likely to be around in a more or less similar set of objects, and their classes are bound to have names that aren't entirely different from the ones coming from the schema. (In the example there is ItemType and Item.) The counter-strategy to adopt here is to enforce a rigid naming convention which should not only deal with class names but also include naming rules for the temporary variables referencing objects of classes from either group.


prev table of contents next