protected void sendInlineEvent(Event event) throws SAXException {
   if (event.type == Event.Type.BEGIN_ELEMENT) {
     super.startElement(event.uri, event.localName, event.qName, event.atts);
   } else if (event.type == Event.Type.END_ELEMENT) {
     super.endElement(event.uri, event.localName, event.qName);
   } else if (event.type == Event.Type.COMMENT) {
     super.comment(event.content.toCharArray(), 0, event.content.length());
   }
 }
  @Override
  public void endDocument() throws SAXException {
    // Flush previous content and print current one
    flushContent();

    super.endDocument();
  }
  @Override
  public void endCDATA() throws SAXException {
    endNonVisibleElement();

    super.endCDATA();

    --fNoCleanUpLevel;
  }
  @Override
  public void comment(char[] ch, int start, int length) throws SAXException {
    if (shouldRemoveWhiteSpaces()) {
      String comment = new String(ch, start, length);

      appendInlineEvent(new Event(comment));
    } else {
      super.comment(ch, start, length);
    }
  }
  @Override
  public void startElement(String uri, String localName, String qName, Attributes atts)
      throws SAXException {
    Attributes clonedAtts = fAttributes.push(new AttributesImpl(atts));

    if (NONVISIBLE_ELEMENTS.contains(qName)) {
      startNonVisibleElement();

      // send start element event
      super.startElement(uri, localName, qName, atts);
    } else {
      if (NONINLINE_ELEMENTS.contains(qName)) {
        // Flush previous content and print current one
        flushContent();

        // white spaces inside pre element are not cleaned
        if ("pre".equalsIgnoreCase(qName)) {
          ++fNoCleanUpLevel;
        }

        // send start element event
        super.startElement(uri, localName, qName, atts);
      } else if (EMPTYVISIBLE_ELEMENTS.contains(localName)) {
        startEmptyVisibleElement();

        super.startElement(uri, localName, qName, atts);
      } else if (preservedInlineContent(localName, atts)) {
        // Flush previous content and print current one
        flushContent(false);

        ++fNoCleanUpLevel;

        // send start element event
        super.startElement(uri, localName, qName, atts);
      } else {
        appendInlineEvent(new Event(uri, localName, qName, clonedAtts));
      }
    }
  }
  @Override
  public void endElement(String uri, String localName, String qName) throws SAXException {
    if (NONVISIBLE_ELEMENTS.contains(qName)) {
      endNonVisibleElement();

      super.endElement(uri, localName, qName);

      --fNoCleanUpLevel;
    } else {
      if (NONINLINE_ELEMENTS.contains(qName)) {
        // Flush previous content and print current one
        flushContent();

        // white spaces inside pre element are not cleaned
        if ("pre".equalsIgnoreCase(qName)) {
          --fNoCleanUpLevel;
        }

        super.endElement(uri, localName, qName);
      } else if (EMPTYVISIBLE_ELEMENTS.contains(qName)) {
        endEmptyVisibleElement();

        super.endElement(uri, localName, qName);
      } else if (preservedInlineContent(localName, fAttributes.peek())) {
        // Flush previous content and print current one
        flushContent();

        --fNoCleanUpLevel;

        super.endElement(uri, localName, qName);
      } else {
        appendInlineEvent(new Event(uri, localName, qName));
      }
    }

    fAttributes.pop();
  }
 protected void sendCharacters(char ch[], int start, int length) throws SAXException {
   if (length > 0) {
     super.characters(ch, start, length);
   }
 }
  @Override
  public void startCDATA() throws SAXException {
    startNonVisibleElement();

    super.startCDATA();
  }