XML parsing with JAXB
From Processing
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
- Annotations tutorial
- JAXB homepage
- Official JAXB tutorial
- Jackson homepage similar to JAXB only using JSON data instead of XML