@Override
    public void startElement(final String uri, final String localName, final String qName, final Attributes atts)
            throws SAXException {

        //if (LOGGER.isTraceEnabled()) {
        //    LOGGER.trace(String.format("startElement called for %s at depth %s, buffer [%s]",
        //            localName, depth, truncateAndStripWhitespace(getBuffer())));
        //}

        try {
            // If depth is 1 then we are entering an event.
            if (rootElement == null) {
                rootElement = localName;
            }

            if (depth == 1) {
                bufferedWriter.flush();
                final CharBuffer cb = stringWriter.getBuffer();

                if (!doneElement) {
                    doneElement = true;

                    if (cb.length() > 0) {
                        // Compensate for the fact that the writer will not have
                        // received a closing bracket as it waits to see if the
                        // current start element will be an empty element. We
                        // will always write root start/end elements as full
                        // elements and not as <elem /> so add the close bracket
                        // here.
                        cb.append('>');

                        // Only allow the header and footer to be set once.
                        if (this.header == null && this.footer == null) {
                            final StringBuilder footerBuilder = new StringBuilder();
                            footerBuilder.append("</");
                            footerBuilder.append(rootElement);
                            footerBuilder.append(">");

                            if (indentOutput) {
                                cb.append('\n');
                                footerBuilder.append('\n');
                            }

                            final String header = cb.toString();
                            final String footer = footerBuilder.toString();
                            //LOGGER.trace(String.format("Setting header [%s] and footer [%s]", header, footer));

                            this.header = header.getBytes(getCharset());
                            this.footer = footer.getBytes(getCharset());
                        }
                    }
                }
                cb.setLength(0);
            }

            // Increase the element depth.
            depth++;

            handler.startElement(uri, localName, qName, atts);

        } catch (final IOException e) {
            throw new SAXException(e);
        } finally {
            super.startElement(uri, localName, qName, atts);
        }
    }
@param uri       the Namespace URI, or the empty string if the element has no
                 Namespace URI or if Namespace processing is not being
                 performed
@param localName the local name (without prefix), or the empty string if
                 Namespace processing is not being performed
@param qName     the qualified name (with prefix), or the empty string if
                 qualified names are not available
@param atts      the attributes attached to the element. If there are no
                 attributes, it shall be an empty Attributes object. The value
                 of this object after startElement returns is undefined
@throws SAXException any SAX exception, possibly wrapping another exception
@see #endElement
@see Attributes
@see AttributesImpl
@see AbstractXMLFilter#startElement(String,
String, String, Attributes)
stroom-pipeline/src/main/java/stroom/pipeline/writer/XMLWriter.java