/**
   * Prints attribute. NOTE: xml:space attribute modifies output format
   *
   * @param name
   * @param value
   * @param isSpecified
   * @exception java.io.IOException
   */
  private void printAttribute(String name, String value, boolean isSpecified, Attr attr)
      throws IOException {

    if (isSpecified || (features & DOMSerializerImpl.DISCARDDEFAULT) == 0) {
      if (fDOMFilter != null && (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ATTRIBUTE) != 0) {
        short code = fDOMFilter.acceptNode(attr);
        switch (code) {
          case NodeFilter.FILTER_REJECT:
          case NodeFilter.FILTER_SKIP:
            {
              return;
            }
          default:
            {
              // fall through
            }
        }
      }
      _printer.printSpace();
      _printer.printText(name);
      _printer.printText("=\"");
      printEscaped(value);
      _printer.printText('"');
    }

    // If the attribute xml:space exists, determine whether
    // to preserve spaces in this and child nodes based on
    // its value.
    if (name.equals("xml:space")) {
      if (value.equals("preserve")) fPreserveSpace = true;
      else fPreserveSpace = _format.getPreserveSpace();
    }
  }
 /**
  * Serializes a namespace attribute with the given prefix and value for URI. In case prefix is
  * empty will serialize default namespace declaration.
  *
  * @param prefix
  * @param uri
  * @exception java.io.IOException
  */
 private void printNamespaceAttr(String prefix, String uri) throws IOException {
   _printer.printSpace();
   if (prefix == XMLSymbols.EMPTY_STRING) {
     if (DEBUG) {
       System.out.println("=>add xmlns=\"" + uri + "\" declaration");
     }
     _printer.printText(XMLSymbols.PREFIX_XMLNS);
   } else {
     if (DEBUG) {
       System.out.println("=>add xmlns:" + prefix + "=\"" + uri + "\" declaration");
     }
     _printer.printText("xmlns:" + prefix);
   }
   _printer.printText("=\"");
   printEscaped(uri);
   _printer.printText('"');
 }
  public void startElement(String tagName, AttributeList attrs) throws SAXException {
    int i;
    boolean preserveSpace;
    ElementState state;
    String name;
    String value;

    if (DEBUG) {
      System.out.println("==>startElement(" + tagName + ")");
    }

    try {
      if (_printer == null) {
        String msg =
            DOMMessageFormatter.formatMessage(
                DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null);
        throw new IllegalStateException(msg);
      }

      state = getElementState();
      if (isDocumentState()) {
        // If this is the root element handle it differently.
        // If the first root element in the document, serialize
        // the document's DOCTYPE. Space preserving defaults
        // to that of the output format.
        if (!_started) startDocument(tagName);
      } else {
        // For any other element, if first in parent, then
        // close parent's opening tag and use the parnet's
        // space preserving.
        if (state.empty) _printer.printText('>');
        // Must leave CData section first
        if (state.inCData) {
          _printer.printText("]]>");
          state.inCData = false;
        }
        // Indent this element on a new line if the first
        // content of the parent element or immediately
        // following an element.
        if (_indenting
            && !state.preserveSpace
            && (state.empty || state.afterElement || state.afterComment)) _printer.breakLine();
      }
      preserveSpace = state.preserveSpace;

      // Do not change the current element state yet.
      // This only happens in endElement().

      _printer.printText('<');
      _printer.printText(tagName);
      _printer.indent();

      // For each attribute print it's name and value as one part,
      // separated with a space so the element can be broken on
      // multiple lines.
      if (attrs != null) {
        for (i = 0; i < attrs.getLength(); ++i) {
          _printer.printSpace();
          name = attrs.getName(i);
          value = attrs.getValue(i);
          if (value != null) {
            _printer.printText(name);
            _printer.printText("=\"");
            printEscaped(value);
            _printer.printText('"');
          }

          // If the attribute xml:space exists, determine whether
          // to preserve spaces in this and child nodes based on
          // its value.
          if (name.equals("xml:space")) {
            if (value.equals("preserve")) preserveSpace = true;
            else preserveSpace = _format.getPreserveSpace();
          }
        }
      }
      // Now it's time to enter a new element state
      // with the tag name and space preserving.
      // We still do not change the curent element state.
      state = enterElementState(null, null, tagName, preserveSpace);
      state.doCData = _format.isCDataElement(tagName);
      state.unescaped = _format.isNonEscapingElement(tagName);
    } catch (IOException except) {
      throw new SAXException(except);
    }
  }
  public void startElement(String namespaceURI, String localName, String rawName, Attributes attrs)
      throws SAXException {
    int i;
    boolean preserveSpace;
    ElementState state;
    String name;
    String value;
    boolean addNSAttr = false;

    if (DEBUG) {
      System.out.println("==>startElement(" + namespaceURI + "," + localName + "," + rawName + ")");
    }

    try {
      if (_printer == null) {
        String msg =
            DOMMessageFormatter.formatMessage(
                DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null);
        throw new IllegalStateException(msg);
      }

      state = getElementState();
      if (isDocumentState()) {
        // If this is the root element handle it differently.
        // If the first root element in the document, serialize
        // the document's DOCTYPE. Space preserving defaults
        // to that of the output format.
        if (!_started)
          startDocument((localName == null || localName.length() == 0) ? rawName : localName);
      } else {
        // For any other element, if first in parent, then
        // close parent's opening tag and use the parnet's
        // space preserving.
        if (state.empty) _printer.printText('>');
        // Must leave CData section first
        if (state.inCData) {
          _printer.printText("]]>");
          state.inCData = false;
        }
        // Indent this element on a new line if the first
        // content of the parent element or immediately
        // following an element or a comment
        if (_indenting
            && !state.preserveSpace
            && (state.empty || state.afterElement || state.afterComment)) _printer.breakLine();
      }
      preserveSpace = state.preserveSpace;

      // We remove the namespaces from the attributes list so that they will
      // be in _prefixes
      attrs = extractNamespaces(attrs);

      // Do not change the current element state yet.
      // This only happens in endElement().
      if (rawName == null || rawName.length() == 0) {
        if (localName == null) {
          String msg =
              DOMMessageFormatter.formatMessage(
                  DOMMessageFormatter.SERIALIZER_DOMAIN, "NoName", null);
          throw new SAXException(msg);
        }
        if (namespaceURI != null && !namespaceURI.equals("")) {
          String prefix;
          prefix = getPrefix(namespaceURI);
          if (prefix != null && prefix.length() > 0) rawName = prefix + ":" + localName;
          else rawName = localName;
        } else rawName = localName;
        addNSAttr = true;
      }

      _printer.printText('<');
      _printer.printText(rawName);
      _printer.indent();

      // For each attribute print it's name and value as one part,
      // separated with a space so the element can be broken on
      // multiple lines.
      if (attrs != null) {
        for (i = 0; i < attrs.getLength(); ++i) {
          _printer.printSpace();

          name = attrs.getQName(i);
          if (name != null && name.length() == 0) {
            String prefix;
            String attrURI;

            name = attrs.getLocalName(i);
            attrURI = attrs.getURI(i);
            if ((attrURI != null && attrURI.length() != 0)
                && (namespaceURI == null
                    || namespaceURI.length() == 0
                    || !attrURI.equals(namespaceURI))) {
              prefix = getPrefix(attrURI);
              if (prefix != null && prefix.length() > 0) name = prefix + ":" + name;
            }
          }

          value = attrs.getValue(i);
          if (value == null) value = "";
          _printer.printText(name);
          _printer.printText("=\"");
          printEscaped(value);
          _printer.printText('"');

          // If the attribute xml:space exists, determine whether
          // to preserve spaces in this and child nodes based on
          // its value.
          if (name.equals("xml:space")) {
            if (value.equals("preserve")) preserveSpace = true;
            else preserveSpace = _format.getPreserveSpace();
          }
        }
      }

      if (_prefixes != null) {
        Enumeration keys;

        keys = _prefixes.keys();
        while (keys.hasMoreElements()) {
          _printer.printSpace();
          value = (String) keys.nextElement();
          name = (String) _prefixes.get(value);
          if (name.length() == 0) {
            _printer.printText("xmlns=\"");
            printEscaped(value);
            _printer.printText('"');
          } else {
            _printer.printText("xmlns:");
            _printer.printText(name);
            _printer.printText("=\"");
            printEscaped(value);
            _printer.printText('"');
          }
        }
      }

      // Now it's time to enter a new element state
      // with the tag name and space preserving.
      // We still do not change the curent element state.
      state = enterElementState(namespaceURI, localName, rawName, preserveSpace);
      name =
          (localName == null || localName.length() == 0) ? rawName : namespaceURI + "^" + localName;
      state.doCData = _format.isCDataElement(name);
      state.unescaped = _format.isNonEscapingElement(name);
    } catch (IOException except) {
      throw new SAXException(except);
    }
  }