@Override
    public void endElement(final String uri, final String localName, final String qName) {

      flushBuffer();

      final NestableNode element = this.elementStack.pop();

      if (this.elementStack.isEmpty()) {
        this.rootNodes.add(element);
      } else {
        final NestableNode parent = this.elementStack.peek();
        parent.addChild(element);
      }
    }
    @Override
    public void comment(final char[] ch, final int start, final int length) throws SAXException {

      if (!this.dtdMode) {

        final Comment comment = new Comment(ArrayUtils.copyOfRange(ch, start, start + length));

        if (this.elementStack.isEmpty()) {
          this.rootNodes.add(comment);
        } else {
          final NestableNode parent = this.elementStack.peek();
          parent.addChild(comment);
        }
      }
    }
    /*
     * Buffer is used for accumulating text that is read in between elements,
     * and should be flushed before creating any non-text element.
     *
     * Note there also is a 'CDATA' buffer, similar in use to this, containing
     * all the contents read for a CDATA section.
     */
    private void flushBuffer() {

      if (this.textBufferLen > 0) {

        final Node textNode =
            new Text(ArrayUtils.copyOf(this.textBuffer, this.textBufferLen), false);

        if (this.elementStack.isEmpty()) {
          this.rootNodes.add(textNode);
        } else {
          final NestableNode parent = this.elementStack.peek();
          parent.addChild(textNode);
        }

        this.textBufferLen = 0;
      }
    }
    @Override
    public void endCDATA() throws SAXException {

      super.endCDATA();

      this.cdataMode = false;
      if (this.cdataBufferLen > 0) {
        Node cdata =
            new CDATASection(ArrayUtils.copyOf(this.cdataBuffer, this.cdataBufferLen), false);
        if (this.elementStack.isEmpty()) {
          this.rootNodes.add(cdata);
        } else {
          final NestableNode parent = this.elementStack.peek();
          parent.addChild(cdata);
        }
        this.cdataBufferLen = 0;
      }
    }