XML parsing with JAXB

From Processing

Jump to: navigation, search

Since the built-in Processing XML library is very rudimentary and cumbersome to use with deeply nested data, here's a brief overview and example sketch of using JAXB to load & save XML data in a much more convenient manner (only 2 lines of code!).

Contents

What is JAXB?

JAXB stands for Java Architecture for XML Binding and has been available since Java 1.5 days, but became fully part of the language with Java 6.0. The framework heavily relies on added metadata (annotations) in your source code in order to automatically map an XML file to a Java class hierarchy. This makes working with XML much more easy, your code more robust and less fault tolerant to the often fuzzy nature of XML data sources with missing elements and/or changing element orders.

XML is a hierarchical data format, always encoding a tree structure. Java classes can also be structured in such a way (and usually are) that they form a tree hierarchy. JAXB makes use of that and handles all (or as much as it can do so) conversions to built-in primitive data types and nested classes, resulting in a fully populated data/class tree when completed. It also supports the Java Collection Framework and therefore can automatically populate & extract the different types of lists available. All of these features are demonstrated below.

JAXB & Processing PDE

Since JAXB relies on syntax only available since Java 1.5 (which actually has been around since 2004), you can't use it with Processing PDE versions prior to 1.2.1. This is because the PDE's pre-processor did not fully support this syntax until recently, so if you're still using one of these older versions, please do upgrade now before continuing with this tutorial...

A first example

The following Processing example will load a simple XML file using JAXB and use the imported data to configure various elements. You can download the entire sketch from here: File:JAXBTest.zip

config.xml

<?xml version="1.0" encoding="UTF-8"?>
<config version="1.0">
  <title>Hello JAXB!</title>
  <message>JAXB - XML the way it was meant to be!</message>
  <width>640</width>
  <height>480</height>
  <bg>ff00ff</bg>
  <url name="Processing">http://processing.org</url>
  <url name="JAXB">http://jaxb.java.net</url>
  <url name="PostSpectacular">http://pspctclr.com</url>
</config>

JAXBTest.pde

/**
 * This example loads a config.xml file in the data folder and uses the information
 * to configure various program options (e.g. window size, color etc.)
 *
 * @author toxi <info at postspectacular dot com>
 *
 * IMPORTANT NOTE:
 * this example will only work in recent versions of Processing, 1.2.1 or newer
 * since the older preprocessor did not support Java annotations
 */
 
// JAXB is part of Java 6.0, but needs to be imported manually
import javax.xml.bind.*;
 
// our little data class for storing config settings
// this class is defined in its own tab in the Processing PDE
AppConfig config;
 
void setup() {
  // the following 2 lines of code will load the config.xml file and map its contents
  // to the nested object hierarchy defined in the AppConfig class (see below)
  try {
    // setup object mapper using the AppConfig class
    JAXBContext context = JAXBContext.newInstance(AppConfig.class);
    // parse the XML and return an instance of the AppConfig class
    config = (AppConfig) context.createUnmarshaller().unmarshal(createInput("config.xml"));
  } catch(JAXBException e) {
    // if things went wrong...
    println("error parsing xml: ");
    e.printStackTrace();
    // force quit
    System.exit(1);
  }
  // here we can be sure the config has been loaded successfully...
  // use settings to define window size
  size(config.width,config.height);
  // set window title
  frame.setTitle(config.title+" v"+config.versionID);
  // list all the urls loaded & their descriptions
  for(MyURL u : config.urls) {
    println(u.name+": "+u.url);
  }
}
 
void draw() {
  // use bg color from config
  background(unhex(config.bg));
  textAlign(CENTER);
  // display config message
  text(config.message,width/2,height/2);
}

AppConfig.java

/////////////////////////////////////////////////////////////////
// IMPORTANT: In the Processing PDE this class needs to be stored
// in its own tab and named "AppConfig.java"
/////////////////////////////////////////////////////////////////
 
import java.util.*;
import javax.xml.bind.annotation.*;
 
// this annoation marks the AppConfig class to be able to act as
// an XML root element. The name parameter is only needed since
// our XML element name is different from the class name:
// <config> vs. AppConfig
 
@XmlRootElement(name="config")
public class AppConfig {
 
  // now we simply annotate the different variables
  // depending if they are XML elements/nodes or node attributes
  // the mapping to the actual data type is done automatically
  @XmlAttribute(name="version")
    float versionID;
 
  // here we also specify default values, which are used
  // if there's no matching data for this variable in the XML
  @XmlElement
    String title="Window title";
 
  @XmlElement
    String message="Hello World!";
 
  @XmlElement
    int width=320;
 
  @XmlElement
    int height=240;
 
  @XmlElement
    String bg="ffffff";
 
  // one of the best things in JAXB is the ability to map entire
  // class hierarchies and collections of data
  // in this case each <url> element will be added to this list
  // the actual MyURL class is defined in its own tab in the Processing PDE
  @XmlElement(name="url")
    List<MyURL> urls=new ArrayList<MyURL>();
}

MyURL.java

/////////////////////////////////////////////////////////////////
// IMPORTANT: In the Processing PDE this class needs to be stored
// in its own tab and named "MyURL.java"
/////////////////////////////////////////////////////////////////
 
import javax.xml.bind.annotation.*;
 
// this class is a simple pairing of 2 strings:
// a url and its description
public class MyURL {
 
  @XmlAttribute
  String name;
 
  @XmlValue
  String url;
}

Resources & further reading

Personal tools