public void pushAttributes(Attributes atts, boolean collectTextFlag) {

    if (attStack.length == elementDepth) {
      // reallocate the buffer
      AttributesImpl[] buf1 = new AttributesImpl[attStack.length * 2];
      System.arraycopy(attStack, 0, buf1, 0, attStack.length);
      attStack = buf1;

      int[] buf2 = new int[idxStack.length * 2];
      System.arraycopy(idxStack, 0, buf2, 0, idxStack.length);
      idxStack = buf2;

      boolean[] buf3 = new boolean[collectText.length * 2];
      System.arraycopy(collectText, 0, buf3, 0, collectText.length);
      collectText = buf3;
    }

    elementDepth++;
    stackTop++;

    // push the stack
    AttributesImpl a = attStack[stackTop];
    if (a == null) attStack[stackTop] = a = new AttributesImpl();
    else a.clear();

    // since Attributes object is mutable, it is criticall important
    // to make a copy.
    // also symbolize attribute names
    for (int i = 0; i < atts.getLength(); i++) {
      String auri = atts.getURI(i);
      String alocal = atts.getLocalName(i);
      String avalue = atts.getValue(i);
      String aqname = atts.getQName(i);

      // work gracefully with misconfigured parsers that don't support namespaces
      if (auri == null) auri = "";
      if (alocal == null || alocal.length() == 0) alocal = aqname;
      if (aqname == null || aqname.length() == 0) aqname = alocal;

      // <foo xsi:nil="false">some value</foo> is a valid fragment, however
      // we need a look ahead to correctly handle this case.
      // (because when we process @xsi:nil, we don't know what the value is,
      // and by the time we read "false", we can't cancel this attribute anymore.)
      //
      // as a quick workaround, we remove @xsi:nil if the value is false.
      if (auri == "http://www.w3.org/2001/XMLSchema-instance" && alocal == "nil") {
        String v = avalue.trim();
        if (v.equals("false") || v.equals("0")) continue; // skip this attribute
      }

      // otherwise just add it.
      a.addAttribute(auri, alocal, aqname, atts.getType(i), avalue);
    }

    // start a new namespace scope
    idxStack[stackTop] = nsLen;

    collectText[stackTop] = collectTextFlag;
  }
  public String eatAttribute(int idx) throws SAXException {
    AttributesImpl a = attStack[stackTop];

    String value = a.getValue(idx);

    // mark the attribute as consumed
    a.removeAttribute(idx);

    return value;
  }
  public void consumeAttribute(int idx) throws SAXException {
    AttributesImpl a = attStack[stackTop];

    String uri = a.getURI(idx);
    String local = a.getLocalName(idx);
    String qname = a.getQName(idx);
    String value = a.getValue(idx);

    // mark the attribute as consumed
    // we need to remove the attribute before we process it
    // because the event handler might access attributes.
    a.removeAttribute(idx);

    getCurrentHandler().enterAttribute(uri, local, qname);
    consumeText(value, false);
    getCurrentHandler().leaveAttribute(uri, local, qname);
  }