/**
   * Serialize the given event data as a standalone XML document
   *
   * @param includeProlog if true, include an XML prolog; if not, just render a document fragment
   * @return the XML serialization, or null if <code>data</code> is null.
   */
  public String serialize(EventDataElement data, boolean includeProlog) {
    if (data == null || data.isNull()) return null;

    try {
      // serialize the DOM to our string buffer.
      XMLStreamWriter writer = factory.createXMLStreamWriter(buffer);
      try {
        if (includeProlog) writer.writeStartDocument();
        serializeElement(writer, data);
        writer.writeEndDocument();
        writer.flush();
      } finally {
        writer.close();
      }

      // return buffer contents.
      return buffer.toString();

    } catch (XMLStreamException ioe) {
      // this shouldn't happen, since the target output stream is a StringWriter, but
      // the compiler demands that we handle it.
      throw new RuntimeException("Error serializing XML data", ioe);
    } finally {

      // reset the internal buffer for next run.
      buffer.getBuffer().setLength(0);
    }
  }
  /** Recursively serialize a single element, appending it to DOM element <code>parent</code>. */
  protected void serializeElement(XMLStreamWriter writer, EventDataElement element)
      throws XMLStreamException {

    if (!element.isNull()) {
      // create a new node for the element and append it to the parent.
      String name = getXMLElementName(element.getName());

      if (element.isEmpty()) {
        writer.writeEmptyElement(name);
        // TODO: remove when stax bug is fixed.
        // this is a workaround for a bug in the 1.2 StAX implementation, where
        // if the only element in your document is empty, the closing "/>" never gets written.
        // any other API call fixes the problem, so here we do a no-op string append to force
        // the element closed.
        writer.writeCharacters(DUMMY_TEXT, 0, 0);
      } else {
        writer.writeStartElement(name);

        // add attributes for properties.
        Iterator<? extends Entry<String, Object>> props = element.iterateProperties();
        while (props.hasNext()) {
          Entry<String, Object> prop = props.next();
          Object value = prop.getValue();
          if (value != null) {
            String propName = getXMLElementName(prop.getKey());
            writer.writeAttribute(propName, value.toString());
          }
        }

        // add text to the element if applicable.
        String text = element.getText();
        if (text != null) writer.writeCharacters(text);

        // add child elements for children.
        Iterator<EventDataElement> children = element.iterateChildren();
        while (children.hasNext()) serializeElement(writer, children.next());
        writer.writeEndElement();
      }
    }
  }