Nux 1.6

nux.xom.io
Interface StreamingSerializer


public interface StreamingSerializer

Using memory consumption close to zero, this interface enables writing arbitrarily large XML documents onto a destination, such as an OutputStream, SAX, StAX, DOM or bnux.

This interface is conceptually similar to the StAX XMLStreamWriter interface, except that it is more XOM friendly, much easier to use (in particular with namespaces), and that implementations are required to guarantee XML wellformedness due to relevant sanity checks. Characters are automatically escaped wherever necessary.

Nodes must be written in document order, starting with writeXMLDeclaration(), followed by writes for the individual nodes, finally finishing with writeEndDocument(). Elements are opened and closed via writeStartTag(Element) and writeEndTag(), respectively.

Implementations of this interface are retrievable via a StreamingSerializerFactory.

If a document can be written successfully it can also be reparsed successfully. Thus, wellformedness checks catch roundtrip bugs early, where they are still cheap to fix: At the sender side rather than the (remote) receiver side.

For example, any attempt to write a document containing namespace conflicts, malformed attribute names or values, multiple or missing root elements, etc. will throw a WellformednessException.

Example usage:

 StreamingSerializerFactory factory = new StreamingSerializerFactory();
 
 StreamingSerializer ser = factory.createXMLSerializer(System.out, "UTF-8");
 // StreamingSerializer ser = factory.createBinaryXMLSerializer(System.out, 0);
 // StreamingSerializer ser = factory.createStaxSerializer(XMLStreamWriter writer);
 
 ser.writeXMLDeclaration();
 ser.writeStartTag(new Element("articles"));
 for (int i = 0; i < 1000000; i++) {
        Element article = new Element("article");
        article.addAttribute(new Attribute("id", String.valueOf(i)));
        ser.writeStartTag(article);
 
        ser.writeStartTag(new Element("prize"));
        ser.write(new Text(String.valueOf(i * 1000)));
        ser.writeEndTag(); // close prize
 
        ser.writeStartTag(new Element("quantity"));
        ser.write(new Text("hello world"));
        ser.writeEndTag(); // close quantity
 
        ser.writeEndTag(); // close article
 }
 ser.writeEndTag(); // close articles
 ser.writeEndDocument();
 

Example usage mixing streaming with convenient writing of entire prefabricated subtrees. For large documents, this approach combines the scalability advantages of streaming with the ease of use of (comparatively small) main-memory subtree construction:

 StreamingSerializerFactory factory = new StreamingSerializerFactory();
 
 StreamingSerializer ser = factory.createXMLSerializer(System.out, "UTF-8");
 // StreamingSerializer ser = factory.createBinaryXMLSerializer(System.out, 0);
 
 ser.writeXMLDeclaration();
 ser.writeStartTag(new Element("articles"));
 for (int i = 0; i < 1000000; i++) {
        Element article = new Element("article");
        article.addAttribute(new Attribute("id", String.valueOf(i)));
 
        Element prize = new Element("prize");
        prize.appendChild(String.valueOf(i * 1000));
        article.appendChild(prize);
 
        Element quantity = new Element("quantity");
        quantity.appendChild("hello world");
        article.appendChild(quantity);
 
        ser.write(article); // writes entire subtree
 }
 ser.writeEndTag(); // close articles
 ser.writeEndDocument();
 

Example writing the following namespaced SOAP message containing arbitrarily many payload numbers in the message body:

  <?xml version="1.0" encoding="UTF-8"?>
  <SOAP:Envelope xmlns:SOAP="http://www.w3.org/2002/06/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP:Header><app:foo xmlns:app="http://example.org"></app:foo></SOAP:Header>
  <SOAP:Body>
  <app:payload xsi:type="decimal" xmlns:app="http://example.org">0</app:payload>
  <app:payload xsi:type="decimal" xmlns:app="http://example.org">1</app:payload>
  <app:payload xsi:type="decimal" xmlns:app="http://example.org">2</app:payload>
  </SOAP:Body>
  </SOAP:Envelope>
 

The above output can be generated as follows:

 StreamingSerializerFactory factory = new StreamingSerializerFactory();
 
 StreamingSerializer ser = factory.createXMLSerializer(System.out, "UTF-8");
 // StreamingSerializer ser = factory.createBinaryXMLSerializer(System.out, 0);
 // StreamingSerializer ser = factory.createStaxSerializer(XMLStreamWriter writer);
 
 String NS_SOAP = "http://www.w3.org/2002/06/soap-envelope";
 String NS_XSI = "http://www.w3.org/2001/XMLSchema-instance";
 String NS_APP = "http://example.org";
 Text lineSeparator = new Text("\n");
 
 // SOAP:Envelope
 ser.writeXMLDeclaration();
 Element envelope = new Element("SOAP:Envelope", NS_SOAP);
 envelope.addNamespaceDeclaration("xsi", NS_XSI);
 ser.writeStartTag(envelope);
 ser.write(lineSeparator);
 
 // SOAP:Header
 Element header = new Element("SOAP:Header", NS_SOAP);
 header.appendChild(new Element("app:foo", NS_APP));
 ser.write(header);
 ser.write(lineSeparator);
 
 // SOAP:Body
 ser.writeStartTag(new Element("SOAP:Body", NS_SOAP));
 
 // begin of user code for writing message payload:
 for (int i = 0; i < 1000000; i++) {
     ser.write(lineSeparator);
     Element payload = new Element("app:payload", NS_APP);
     payload.addAttribute(new Attribute("xsi:type", NS_XSI, "decimal"));
     payload.appendChild(new Text(String.valueOf(i)));
     ser.write(payload);
 }
 // end of user code
 
 ser.write(lineSeparator);
 ser.writeEndTag(); // close SOAP:Body
 ser.write(lineSeparator);
 ser.writeEndTag(); // close SOAP:Envelope
 ser.writeEndDocument();
 

Author:
whoschek.AT.lbl.DOT.gov, $Author: hoschek3 $

Method Summary
 void flush()
          Forces any bytes buffered by the implementation to be written onto the underlying destination.
 void write(Comment comment)
          Writes the given comment node.
 void write(DocType docType)
          Writes the given document type node.
 void write(Document doc)
          Recursively writes the entire given prefabricated document, including the XML declaration and all its descendants.
 void write(Element element)
          Recursively writes the entire subtree rooted at the given (potentially parentless) element; this includes attributes and namespaces as if recursively calling writeStartTag/write/writeEndTag for this element and all its descendants, in document order.
 void write(ProcessingInstruction instruction)
          Writes the given processing instruction node.
 void write(Text text)
          Writes the given text node.
 void writeEndDocument()
          Finishes writing the current document, auto-closing any remaining open element tags via writeEndTag calls; Implicitly calls flush() and releases resources.
 void writeEndTag()
          Writes the corresponding closing end tag for the element handed to the last writeStartTag call.
 void writeStartTag(Element elem)
          Writes the start tag for the given (potentially parentless) element; this excludes children and includes attributes and namespaces defined on this element, as if the element had as parent the element handed to the last writeStartTag call.
 void writeXMLDeclaration()
          Writes the standard XML declaration (including XML version and encoding); must be called before any other write flavour except write(Document).
 

Method Detail

flush

void flush()
           throws IOException
Forces any bytes buffered by the implementation to be written onto the underlying destination.

Throws:
IOException - if the underlying destination encounters an I/O error

writeStartTag

void writeStartTag(Element elem)
                   throws IOException
Writes the start tag for the given (potentially parentless) element; this excludes children and includes attributes and namespaces defined on this element, as if the element had as parent the element handed to the last writeStartTag call.

Corresponding closing end tags should be written via writeEndTag. A correct program must emit the same number of writeStartTag and writeEndTag calls.

The value of elem.getParent() is ignored. Instead, the (virtual) parent is considered to be the element passed to the last corresponding writeStartTag(Element) call. If there's no such last corresponding writeStartTag call, then the (virtual) parent is considered to be a (virtual) document node.

Parameters:
elem - the element to write a start tag for
Throws:
IOException - if the underlying destination encounters an I/O error

writeEndTag

void writeEndTag()
                 throws IOException
Writes the corresponding closing end tag for the element handed to the last writeStartTag call.

Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(Document doc)
           throws IOException
Recursively writes the entire given prefabricated document, including the XML declaration and all its descendants. This isn't particularly meaningful in a streaming scenario, and only available for completeness and ease of use.

Parameters:
doc - the document to write
Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(Element element)
           throws IOException
Recursively writes the entire subtree rooted at the given (potentially parentless) element; this includes attributes and namespaces as if recursively calling writeStartTag/write/writeEndTag for this element and all its descendants, in document order.

For large documents, this method combines the scalability advantages of streaming with the ease of use of (comparatively small) main-memory subtree construction.

Parameters:
element - the root of the subtree to write
Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(Text text)
           throws IOException
Writes the given text node.

Parameters:
text - the node to write
Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(Comment comment)
           throws IOException
Writes the given comment node.

Parameters:
comment - the node to write
Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(ProcessingInstruction instruction)
           throws IOException
Writes the given processing instruction node.

Parameters:
instruction - the node to write
Throws:
IOException - if the underlying destination encounters an I/O error

write

void write(DocType docType)
           throws IOException
Writes the given document type node.

Parameters:
docType - the node to write
Throws:
IOException - if the underlying destination encounters an I/O error

writeEndDocument

void writeEndDocument()
                      throws IOException
Finishes writing the current document, auto-closing any remaining open element tags via writeEndTag calls; Implicitly calls flush() and releases resources.

Throws:
IOException - if the underlying destination encounters an I/O error

writeXMLDeclaration

void writeXMLDeclaration()
                         throws IOException
Writes the standard XML declaration (including XML version and encoding); must be called before any other write flavour except write(Document).

Throws:
IOException - if the underlying destination encounters an I/O error

Nux 1.6