Articles / Using XmlBeans to parse EPCIS events

Back to Tech Articles

Created : 21 May 2007
Last updated :

Background

RFID tags are increasingly used to track supply chains. This is accomplished by when tagged subjects move through tag readers. The readers send signals to a RFID middleware that collects this signals and send events in nicely formatted XML format. I refer these XML events as Epcis Events. They events conform to an XML schema, making it easy to decode them. XMLBeans provides a nice way to deal with XML elements via Java objects. In this article I will show how to use parse the events using XML Beans

Setup

We need the following

  1. XML Beans library (from Apache)
  2. XML schemas for the Epcis Events  (from EpcisInc)
  3. generate XMLBeans for the events (ant file)
  4. Java code snippets to show the usage
Here is the zip file containing an Eclipse project with all the files needed.
 epcglobal-xmlbeans.zip
Just import this zip file into Eclipse as a project and you are set to go.  The project is strcutured as below

Making XMLBeans out of Schemas

The following section in the ant file does the compiling

 <xmlbean schema="schemas"
            destfile="${schema.jarfile}"
            srcgendir="build/src"
            classpathref="xmlbeans.path"
            debug="on"
            />

This generated bunch of Java files from Schema files and put them in a JAR file.

Go into the project directory and invoke ANT, or in Eclipse right click on the build.xml file and say 'Run As --> Ant'.  You would see something similar to the following output

ant

Buildfile: /home/sujee/workspaces/default/epcglobal_xmlbeans/build.xml
init:
     [echo] xmlbeans.home: xmlbeans-2.2.0
clean:
jar:
    [mkdir] Created dir: /home/sujee/workspaces/default/epcglobal_xmlbeans/build
  [xmlbean] Time to build schema type system: 1.434 seconds
  [xmlbean] Time to generate code: 0.338 seconds
  [xmlbean] Compiling 116 source files to /tmp/xbean33945.d/classes
  [xmlbean] Time to compile code: 3.648 seconds
  [xmlbean] Building jar: /home/sujee/workspaces/default/epcglobal_xmlbeans/lib/schemas.jar
   [delete] Deleting directory /home/sujee/workspaces/default/epcglobal_xmlbeans/build
build:
BUILD SUCCESSFUL
Total time: 6 seconds

 'Refresh' the Eclipse project for changes to take effect.  Lets explore the generated classes

As can be seen from the image above right, the generated Java Interfaces/Class hierarchy models the EpcisEvent hiearchy.  Epcis standard defines four kinds of events

  1. Aggregation Event
  2. Object Event
  3. Quantity Event
  4. Transaction Event

Explore type hiearchy in Eclipse


event class hierarchy



With generated Java types, dealing with the event XML is lot easier. Lets get down to the Java code

Java code

// imports
import java.io.FileReader;
import java.util.Calendar;
import org.unece.cefact.namespaces.standardBusinessDocumentHeader.StandardBusinessDocumentHeader;
import epcglobalEpcisXsd1.*;


	EPCISDocumentDocument1 epcisDoc = EPCISDocumentDocument1.Factory
			.parse(new FileReader("events/all-events.xml"));
	EPCISDocumentType docType = epcisDoc.getEPCISDocument();
	// header
	EPCISHeaderType header = docType.getEPCISHeader();
	StandardBusinessDocumentHeader bizHeader = header.getStandardBusinessDocumentHeader();
	String version = bizHeader.getHeaderVersion();
	
	// events
	// lets just get the first of each events
	// and examine some of the attributes for each event
	EPCISBodyType body = docType.getEPCISBody();
	EventListType eventList = body.getEventList();

	// --------- read events
	// Aggregation Event
	AggregationEventType aggEvent = eventList.getAggregationEventArray(0);
	// event time and record time are available for all events
	Calendar recordTime = aggEvent.getRecordTime();
	Calendar eventTime = aggEvent.getEventTime();

	String parentID = aggEvent.getParentID();
	EPCListType childEpcs = aggEvent.getChildEPCs();

	// Object Event
	ObjectEventType objEvent = eventList.getObjectEventArray(0);
	String action = objEvent.getAction().toString();

	// Quantiy Event
	QuantityEventType quanEvent = eventList.getQuantityEventArray()[0];
	int quantity = quanEvent.getQuantity();

	// Transaction event
	TransactionEventType transEvent = eventList.getTransactionEventArray(0);
	BusinessTransactionListType bizTrans = transEvent.getBizTransactionList();


The root of the document is EpcisDocumentDocument1.  We get that root object, by parsing the xml using the Factory provided by that Interface.  Then we just traverse the document down using getters (generated by XMLBeans).  THe snippet shows how to get four core types of Epcis events and getting some of the attributes.

Setting Values

We don't have to stop at just inspecting values of events.  XMLBeans provides just as easy APIs to set values as well.  Say you want to change the 'RecordTime' of events to reflect when they were captured by the application.  'setRecordTime' function accomlishes that.

	
	Calendar now = Calendar.getInstance();
	objEvent.setRecordTime(now);

(There could be a small confusion understanding EventTime and  RecordTime.  EventTime is when the event actually occured - i.e. when the tagged subject passed through the reader creating the event.  EventTime doesn't change.  RecordTime may be used to indicate when the event was recorded into an Epcis repository via an application)


Extensions

Epcis standard leaves room for future expansion in the events.  There are two kinds of extensions.  Standard Extension and Vendor Extension.  Standard Extensions already go into the <extension> section.  Vendor extension how ever will follow standard elements.  Vendor extensions can not be declared in the same namespaces of epcis elements, they will have to declared within their own namespace.
<?xml version="1.0" encoding="UTF-8"?>
<epcis:EPCISDocument xmlns:epcglobal="urn:epcglobal:xsd:1" 
                                         xmlns:epcis="urn:epcglobal:epcis:xsd:1" 
                                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                                         xmlns:foo="http://foo" 
                                         xmlns:bar="http://bar">
  <EPCISBody>
    <EventList>
      <ObjectEvent>
        <eventTime>2006-05-16T17:57:26Z</eventTime>
        <!-- .... usual attributes .... -->
        <extension>
          <!-- standard extensions go here -->
          <temperature>30.1C</temperature>
        </extension>
        <!-- vendor extensions follow, they are in their own namespace -->
        <foo:newFOOExtension>Value_FOO</foo:newFOOExtension>
        <bar:newBARExtension>
          <bar:barhello>Bar Hello </bar:barhello>
        </bar:newBARExtension>
      </ObjectEvent>


     </EventList>
  </EPCISBody>
</epcis:EPCISDocument>


The schema defines extensions as follows (notice how Vendor Extensions have ##other namespace)

<xsd:complexType name="ObjectEventType">
        <xsd:annotation>
                <xsd:documentation xml:lang="en">
                Object Event captures information about an event pertaining to one or more
                objects identified by EPCs.
        </xsd:documentation>
        </xsd:annotation>
        <xsd:complexContent>
                <xsd:extension base="epcis:EPCISEventType">
                        <xsd:sequence>
                                <xsd:element name="epcList" type="epcis:EPCListType"/>
                                <xsd:element name="action" type="epcis:ActionType"/>
                                <xsd:element name="bizStep" type="epcis:BusinessStepIDType" minOccurs="0"/>
                                <xsd:element name="disposition" type="epcis:DispositionIDType" minOccurs="0"/>
                                <xsd:element name="readPoint" type="epcis:ReadPointType" minOccurs="0"/>
                                <xsd:element name="bizLocation" type="epcis:BusinessLocationType" minOccurs="0"/>
                                <xsd:element name="bizTransactionList" type="epcis:BusinessTransactionListType" minOccurs="0"/>
                                <xsd:element name="extension" type="epcis:ObjectEventExtensionType" minOccurs="0"/>
                                <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                        </xsd:sequence>
                        <xsd:anyAttribute processContents="lax"/>
                </xsd:extension>
        </xsd:complexContent>
        </xsd:complexType>

Getting Standard Extension is pretty straightforward.

	// standard extension
	ObjectEventExtensionType ext = objEvent.getExtension();
	//	get the DOM Node
	Node extNode = ext.getDomNode();
	// or get it as string
	String extStr = ext.toString();
	// pretty output
	XmlOptions xmlopts = new XmlOptions();
	xmlopts.setSaveOuter();
	xmlopts.setSavePrettyPrint(); 
	String extStr2 = ext.xmlText(xmlopts);


We can get the extension as a XML DOM node or a String.  This is good, but how can we process elements within extension?

One approach is to resort to old fashioned XML parsing using DOM Nodes as we can get the DOM node for extension.

If we know the schema (structure) of elements within extension - and this is not defined in Epcis schema, so iwe have to know this from other sources - then we can utilize XMLBeans here as well.  Think of this like Russian Dolls that are stacked within each other
  1. First generate XMLBeans for Extension-Schema using schema files for the extension (look at the ANT file for example)
  2. Feed the extension to the new Schema Factory.  In the code  below lets assume the root class is 'MyExtRoot'.
    This code illustrates how flexible XMLBeans is.  not only it can parse whole XMLDocuments, but it can consume XML fragments as well.  These fragments can be String or event DOM nodes

	//Looking into extension
	// feed the extension to new Schema parser
	MyExtRoot.Factory.parse (new StringReader (extStr));
	// or you can feed the DOM Node
	MyExtRoot.Factory.parse (extNode);
	// or any children of node
	MyExtRoot.Factory.parse (extNode.getFirstChild ());


Vendor Extensions
Vendor extensions are defined as
 <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
Again, we can use use plain XML Parsing to process the content.

	/// vendor extension
	// doing DOM processing, get the next element after 'extNode'
	Node n = extNode.getNextSibling();
	while  ( (n != null) && !(n instanceof Element))
		n = n.getNextSibling();
	// now 'n' has the first node of Vendor extension '<foo:newFOOExtension>'
	Node vendorExtNode = n;

Lets use XMLBeans to access the same. We are going to select all Elements that fall into '##other' namespace. We do this by creating a 'Wild card Qname'

	// xmlbeans way
	QNameSet qns = QNameSet.forWildcardNamespaceString("##other", "*");
	// get them as xmlObjects 
	XmlObject[] newExts = objEvent.selectChildren(qns);
	// make them into an string
	StringBuffer buf = new StringBuffer();
	// if we use TOSTRING then only 'xml-fragments' are printed out.
	// use xmlText with XMLOptions to get full element printout
	XmlOptions xmlopts2 = new XmlOptions();
	xmlopts2.setSaveOuter();
	xmlopts2.setSavePrettyPrint();
	for (int i = 0; (newExts != null) && (i < newExts.length); i++) {
		buf.append(newExts[i].xmlText(xmlopts2)).append("\n");
	}
	String vendorExtStr = buf.toString();


Pretty easy, eh? Also take a look at other 'selectChildren' methods available in XMLBeans

Summary

We have looked at how to use XMLBeans to easily access (get and set) to contents of Epcis events.  We have seen code snippets to access standard attributes and also extension attributes of events.


References / Further Reading / Credits


** Comment on this article **