/**
   * Returns the Attr[]s to be outputted for the given element. <br>
   * The code of this method is a copy of {@link #handleAttributes(Element, NameSpaceSymbTable)},
   * whereas it takes into account that subtree-c14n is -- well -- subtree-based. So if the element
   * in question isRoot of c14n, it's parent is not in the node set, as well as all other ancestors.
   *
   * @param E
   * @param ns
   * @return the Attr[]s to be outputted
   * @throws CanonicalizationException
   */
  Iterator handleAttributesSubtree(Element E, NameSpaceSymbTable ns)
      throws CanonicalizationException {
    if (!E.hasAttributes() && !firstCall) {
      return null;
    }
    // result will contain the attrs which have to be outputted
    final SortedSet result = this.result;
    result.clear();
    NamedNodeMap attrs = E.getAttributes();
    int attrsLength = attrs.getLength();

    for (int i = 0; i < attrsLength; i++) {
      Attr N = (Attr) attrs.item(i);
      String NUri = N.getNamespaceURI();

      if (XMLNS_URI != NUri) {
        // It's not a namespace attr node. Add to the result and continue.
        result.add(N);
        continue;
      }

      String NName = N.getLocalName();
      String NValue = N.getValue();
      if (XML.equals(NName) && XML_LANG_URI.equals(NValue)) {
        // The default mapping for xml must not be output.
        continue;
      }

      Node n = ns.addMappingAndRender(NName, NValue, N);

      if (n != null) {
        // Render the ns definition
        result.add(n);
        if (C14nHelper.namespaceIsRelative(N)) {
          Object exArgs[] = {E.getTagName(), NName, N.getNodeValue()};
          throw new CanonicalizationException("c14n.Canonicalizer.RelativeNamespace", exArgs);
        }
      }
    }

    if (firstCall) {
      // It is the first node of the subtree
      // Obtain all the namespaces defined in the parents, and added to the output.
      ns.getUnrenderedNodes(result);
      // output the attributes in the xml namespace.
      xmlattrStack.getXmlnsAttr(result);
      firstCall = false;
    }

    return result.iterator();
  }
  /**
   * Returns the Attr[]s to be outputted for the given element. <br>
   * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a DOM which has been
   * prepared using {@link
   * com.sun.org.apache.xml.internal.security.utils.XMLUtils#circumventBug2650(
   * org.w3c.dom.Document)}.
   *
   * @param E
   * @param ns
   * @return the Attr[]s to be outputted
   * @throws CanonicalizationException
   */
  Iterator handleAttributes(Element E, NameSpaceSymbTable ns) throws CanonicalizationException {
    // result will contain the attrs which have to be outputted
    xmlattrStack.push(ns.getLevel());
    boolean isRealVisible = isVisibleDO(E, ns.getLevel()) == 1;
    NamedNodeMap attrs = null;
    int attrsLength = 0;
    if (E.hasAttributes()) {
      attrs = E.getAttributes();
      attrsLength = attrs.getLength();
    }

    SortedSet result = this.result;
    result.clear();

    for (int i = 0; i < attrsLength; i++) {
      Attr N = (Attr) attrs.item(i);
      String NUri = N.getNamespaceURI();

      if (XMLNS_URI != NUri) {
        // A non namespace definition node.
        if (XML_LANG_URI == NUri) {
          xmlattrStack.addXmlnsAttr(N);
        } else if (isRealVisible) {
          // The node is visible add the attribute to the list of output attributes.
          result.add(N);
        }
        // keep working
        continue;
      }

      String NName = N.getLocalName();
      String NValue = N.getValue();
      if ("xml".equals(NName) && XML_LANG_URI.equals(NValue)) {
        /* except omit namespace node with local name xml, which defines
         * the xml prefix, if its string value is http://www.w3.org/XML/1998/namespace.
         */
        continue;
      }
      // add the prefix binding to the ns symb table.
      // ns.addInclusiveMapping(NName,NValue,N,isRealVisible);
      if (isVisible(N)) {
        if (!isRealVisible && ns.removeMappingIfRender(NName)) {
          continue;
        }
        // The xpath select this node output it if needed.
        // Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible);
        Node n = ns.addMappingAndRender(NName, NValue, N);
        if (n != null) {
          result.add(n);
          if (C14nHelper.namespaceIsRelative(N)) {
            Object exArgs[] = {E.getTagName(), NName, N.getNodeValue()};
            throw new CanonicalizationException("c14n.Canonicalizer.RelativeNamespace", exArgs);
          }
        }
      } else {
        if (isRealVisible && NName != XMLNS) {
          ns.removeMapping(NName);
        } else {
          ns.addMapping(NName, NValue, N);
        }
      }
    }
    if (isRealVisible) {
      // The element is visible, handle the xmlns definition
      Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
      Node n = null;
      if (xmlns == null) {
        // No xmlns def just get the already defined.
        n = ns.getMapping(XMLNS);
      } else if (!isVisible(xmlns)) {
        // There is a definition but the xmlns is not selected by the xpath.
        // then xmlns=""
        n = ns.addMappingAndRender(XMLNS, "", nullNode);
      }
      // output the xmlns def if needed.
      if (n != null) {
        result.add(n);
      }
      // Float all xml:* attributes of the unselected parent elements to this one.
      // addXmlAttributes(E,result);
      xmlattrStack.getXmlnsAttr(result);
      ns.getUnrenderedNodes(result);
    }

    return result.iterator();
  }