PUBLIC NOTICE

NOTE: This tutorial page HAS MOVED to http://wiki.fasterxml.com/StaxMateTutorial.


5 Minute Tutorial for StaxMate

As per introduction, StaxMate is designed to allow

To see what this means in action, let's have a look at simple sample use cases.

Writing an XML document

Let's start with a particular simple and common use case: that of writing (aka generating) XML content. Content can come from variety of sources; here we only consider generation, not where data comes from.

Let's say we want to output XML document like this one:

<!-- generated: [CURRENT TIME]-->
<employee id="123">
  <name>
    <first>Tatu</first>
    <last>Saloranta</last>
  </name>
</employee>

Let's first look at one possible piece of code to output such a document:

// 1: need output factory
SMOutputFactory outf = new SMOutputFactory(XMLOutputFactory.newInstance());
SMOutputDocument doc = outf.createOutputDocument(new File("empl.xml"));
// (optional) 3: enable indentation (note spaces after backslash!)
doc.setIndentation("\n  ", 1, 1);
// 4. comment regarding generation time
doc.addComment(" generated: "+new java.util.Date().toString());
SMOutputElement empl = doc.addElement("employee");
empl.addAttribute(/*namespace*/ null, "id", 123);
SMOutputElement name = empl.addElement("name");
name.addElement("first").addCharacters("Tatu");
name.addElement("last").addCharacters("Saloranta");
// 10. close the document to close elements, flush output
doc.closeRoot();

So how does that work? Here is what is being done and why:

  1. First we create a StaxMate output factory: here we use automatic introspection that Stax XMLOutputFactory offers (to find any plugged implementation)
  2. Create the document output object. Document object just denotes document itself, not a root element: but we will add the root element under it (could also add comments, processing instructions). In this case, we will write an xml file.
  3. We can also choose to "pretty print" output document, by enabling indentation.
  4. It is often useful to add xml comments that include developer-readable information about generator process; it is easily ignored by xml readers
  5. Add Employee element
  6. Add attribute 'id' with typed value (StaxMate can convert from number to String)
  7. Add 'name' element
  8. Add both 'first' element and its textual contents
  9. Add similarly, 'last' and its textual contents
  10. Important: MUST close the root-level object; otherwise start elements may not get closed, contents not flushed to the file.

Some things to consider:

Reading XML content

Now that we have written some XML content, let's read it back in.
Let's start with the code (that uses xml document that we saw earlier):

// 1: need input factory
SMInputFactory inf = new SMInputFactory(XMLInputFactory.newInstance());
// 2: and root cursor that reads XML document from File:
SMHierarchicCursor rootC = inf.rootElementCursor(new File("empl.xml"));
rootC.advance; // note: 2.0 only method; can also call ".getNext()"
int employeeId = rootC.getAttrIntValue(0);
SMHierarchicCursor nameC = rootC.childElementCursor("name").advance();
SMHierarchicCursor leafC = nameC.childElementCursor().advance();
String first = leafC.collectDescendantText(false);
leafC.advance();
String last = leafC.collectDescendantText(false);
rootC.getStreamReader().closeCompletely()

So how does that work? Here is what is being done and why:

  1. First we create a StaxMate input factory: similar to constructing output factory
  2. Create the root cursor; only traverses over the root element, ignores non-elements like comments
  3. Cursors are initially not positioned over an event, need to advance
  4. Since we know cursor must point to root element, we can access employee id attribute
  5. Need to create a cursor for traversing, filter out all except "name" elements, advance to the first (and only) "name" child element
  6. construct the innermost cursor for traversing immediate children of "name", advance to the first child ("first")
  7. collect all textual content
  8. advance to the second child ("second")
  9. collect all textual content
  10. close the underlying stream reader (important!)

Here are some more things to consider:

Better than Stax 1.0?

Since the original claim was that StaxMate makes things more convenient, let's see what equivalent code for writein would look like, if we didn't have StaxMate:

// 1: need output factory, writer
XMLOutputFactory outf = XMLOutputFactory.newInstance());
FileOutputStream fos = new FileOutputStream(new File("empl.xml"));
XMLStreamWriter xw = outf.createXMLStreamWriter(fos, "UTF-8");
// No way to do automated indentation: must write manually
xw.writeStartDocument(); // not needed with StaxMate
xw.writeComment(" generated: "+new java.util.Date().toString());
xw.writeStartElement("employee");
String idStr = String.valueOf(123);
xw.writeAttribute("id", idStr);
xw.writeCharacters("\n  "); // indent
xw.writeStartElement("name");
xw.writeCharacters("\n    "); // indent
xw.writeStartElement("first");
xw.writeCharacters("Tatu");
xw.writeEndElement(); // for first
xw.writeCharacters("\n    "); // indent
xw.writeStartElement("last");
xw.writeCharacters("Saloranta");
xw.writeEndElement(); // for last
xw.writeCharacters("\n  "); // indent
xw.writeEndElement(); // for name
xw.writeCharacters("\n"); // indent
xw.writeEndElement(); // for employee
xw.writeEndDocument();
xw.close(); // as per Stax 1.0, won't close stream!
fos.close(); // so we need this too

So what does this tell us?

Similarly we could show the alternative for reading XML content: but unfortunately that code would be even more verbose. So to keep this tutorial brief, we'll leave that exercise to readers.

Advanced Use Cases

Here are links to some use cases that show more advanced usage:

TO BE COMPLETED