Working with XML

In this section we'll show how to create XML. XML (or better an XML document) exists in various flavours: You might want to have it serialized into a String. Sometimes you may prefer character or byte streams, aka instances of Writer or OutputStream. In other cases you will prefer a DOM representation. The main things of interest are: How to I create a serialized XML document (a String, a character or byte stream)? And, vice versa, how do I read such a document and convert it back into Java objects?

Writing XML documents

In the case of JaxMe you'll have simple Java beans. An address is created by instantiating a class AddressImpl, which is implementing an interface Address. For example:

import java.io.FileWriter;
import java.io.Writer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import net.sf.jaxme.examples.misc.address.Address;
import net.sf.jaxme.examples.misc.address.AddressType.EmailDetailsType.EmailType;
import net.sf.jaxme.examples.misc.address.AddressType.PhoneDetailsType.PhoneType;
import net.sf.jaxme.examples.misc.address.impl.AddressImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.EmailDetailsTypeImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.EmailDetailsTypeImpl.EmailTypeImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.PhoneDetailsTypeImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.PhoneDetailsTypeImpl.PhoneTypeImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.NameTypeImpl;
import net.sf.jaxme.examples.misc.address.impl.AddressTypeImpl.PostalTypeImpl;
public class AddressCreator {
  public static void writeAddress(Writer pWriter) throws JAXBException {
    // Create the element:
    Address addr = new AddressImpl();
    addr.setName(new NameTypeImpl());
    addr.getName().setFirst("Jane");
    addr.getName().setLast("Doe");
    addr.setPostal(new PostalTypeImpl());
    addr.getPostal().setStreet("34 Main Street");
    addr.getPostal().setCity("Boston");
    addr.getPostal().setState("MA");
    addr.getPostal().setZIP("02215");
    addr.setEmailDetails(new EmailDetailsTypeImpl());

    /* Lots of similar lines omitted for brevity ...
     * ...
     */

    // And save it into the file "Address.xml"
    JAXBContext context = JAXBContext.newInstance("net.sf.jaxme.examples.misc.address");
    Marshaller marshaller = context.createMarshaller();
    marshaller.marshal(addr, pWriter);
  }

  public static void main(String[] args) throws Exception {
    FileWriter fw = new FileWriter("Address.xml");
    writeAddress(fw);
    fw.close();
  }
}
        
The example is quoted from the file src/java/net/sf/jaxme/examples/misc/address/AddressCreator.java, which comes to you as part of the JaxMe distribution.

There are several things you should note here:

  • The class and property names are obviously taken from element and attribute names.
  • Although the Address document uses namespaces, attributes, and child elements, the example requires by no means knowledge of XML. For example, you do not need to care for character escaping.
  • Complex child elements are java beans themselves, like the Address element. For example, the Name element has to be instantiated
  • To convert the object into an XML string, the JAXBContext and Marshaller are used. These are objects specified by the JAXB specification. The example uses no JaxMe specific features and should in practice run with any JAXB implementation.

Reading XML

The example on writing XML was surprisingly simple. In fact, the only nasty part was creating the object, which requires invocation of lots of setters and getters. Quite opposed to the marshalling, which took place in three lines. And, as we soon will see: Unmarshalling (the process of reading a document) is by no means more complex.

To demonstrate the unmarshalling process, we'll quote an example from the JaxMe distribution again. This time it's the file src/java/net/sf/jaxme/examples/misc/address/AddressPrinter.java:

package net.sf.jaxme.examples.misc.address;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import net.sf.jaxme.examples.misc.address.Address;
import org.xml.sax.InputSource;


public class AddressPrinter {
  public static Address getAddress(InputSource pSource) throws JAXBException {
    JAXBContext context = JAXBContext.newInstance("net.sf.jaxme.examples.misc.address");
    Unmarshaller unmarshaller = context.createUnmarshaller();
    return (Address) unmarshaller.unmarshal(pSource);
  }

  public static String getAddressAsString(Address pAddress) throws JAXBException {
    StringWriter sw = new StringWriter();
    JAXBContext context = JAXBContext.newInstance("net.sf.jaxme.examples.misc.address");
    Marshaller marshaller = context.createMarshaller();
    marshaller.marshal(pAddress, sw);
    return sw.toString();
  }

  public static void main(String[] args) throws Exception {
    File f = new File("Address.xml");
    InputSource isource = new InputSource(new FileInputStream(f));
    isource.setSystemId(f.toURL().toString());
    Address addr = getAddress(isource);

    // A simpler variant might be:
    // Address addr = unmarshaller.unmarshal(f);

    if (addr.getName() == null) {
      System.out.println("Loaded address without name.");
    } else {
      System.out.println("Loaded address " + addr.getName().getLast() +
                         ", " + addr.getName().getFirst() + ".");
    }
    System.out.println("Details:" + getAddressAsString(addr));
  }
}
          

What the example does (see the method main())

  1. It reads the file Address.xml. This is the very same file, which we have created in the first example.
  2. It creates an instance of InputSource. The InputSource is specified by the SAX API and can be viewed as an abstraction of the data source where to read XML from, typically an InputStream or a Writer.
  3. The method getAddress() is invoked to convert the XML document into an instance of Address. These are the promised three lines, again using classes and methods from JAXB.
  4. Finally the method getAddressAsString is invoked to convert the Address instance back into a printable String, which we may use to verify that everything went fine. (It is always nice to see a result being displayed on the screen. :-)