/**
   * Creates a (possibly empty) <CODE>NodeList</CODE> containing all the element nodes identified by
   * the given name strings.
   *
   * @param names An array of name strings for elements.
   * @return A <CODE>NodeList</CODE> of corresponding nodes.
   * @since TFP 1.0
   */
  public NodeList getElementsByName(final String[] names) {
    MutableNodeList result = new MutableNodeList();

    for (int index = 0; index < names.length; ++index)
      result.addAll(getElementsByName(names[index]));

    return (result);
  }
  /**
   * Creates a (possibly empty) <CODE>NodeList</CODE> containing all the element nodes of a given
   * type (or a derived sub-type).
   *
   * @param ns The required namespace URI.
   * @param type The required type name.
   * @return A <CODE>NodeList</CODE> of corresponding nodes.
   * @since TFP 1.1
   */
  public NodeList getElementsByType(final String ns, final String type) {
    Vector<TypeInfo> matches = compatibleTypes.get(type);

    if (matches == null) {
      compatibleTypes.put(type, matches = new Vector<TypeInfo>());

      //			System.err.println ("%% Looking for " + ns + ":" + type);

      Enumeration<String> cursor = typesByName.keys();
      while (cursor.hasMoreElements()) {
        String key = (String) cursor.nextElement();
        Vector<TypeInfo> types = typesByName.get(key);

        for (int index = 0; index < types.size(); ++index) {
          TypeInfo info = types.elementAt(index);

          if (type.equals(info.getTypeName())
              || info.isDerivedFrom(
                  ns, type, TypeInfo.DERIVATION_EXTENSION | TypeInfo.DERIVATION_RESTRICTION)) {
            matches.add(info);
            //						System.err.println ("%% Found: " + info.getTypeName ());
          }
        }
      }
    }

    MutableNodeList result = new MutableNodeList();

    for (int index = 0; index < matches.size(); ++index) {
      TypeInfo info = matches.elementAt(index);
      NodeList nodes = elementsByType.get(info.getTypeName());

      //			System.err.println ("-- Matching elements of type: " + info.getTypeName ());

      for (int count = 0; count < nodes.getLength(); ++count) {
        Element element = (Element) nodes.item(count);
        TypeInfo typeInfo = element.getSchemaTypeInfo();

        if (typeInfo.getTypeName().equals(info.getTypeName())
            && typeInfo.getTypeNamespace().equals(info.getTypeNamespace())) {
          result.add(element);

          //					System.err.println ("-- Matched: " + element.getLocalName ());
        }
      }
    }

    return (result);
  }
  /**
   * Recursively walks a DOM tree creating an index of the elements by their local name.
   *
   * @param node The next node to be indexed.
   * @since TFP 1.0
   */
  private void indexNodes(Node node) {
    switch (node.getNodeType()) {
      case Node.DOCUMENT_NODE:
        indexNodes(((Document) node).getDocumentElement());
        break;

      case Node.ELEMENT_NODE:
        {
          String name = ((Element) node).getLocalName();

          MutableNodeList list = (MutableNodeList) elementsByName.get(name);

          if (list == null) elementsByName.put(name, list = new MutableNodeList());

          list.add(node);

          TypeInfo typeInfo = ((Element) node).getSchemaTypeInfo();
          if ((typeInfo != null) && ((name = typeInfo.getTypeName()) != null)) {
            Vector<TypeInfo> types = typesByName.get(name);
            int index;

            if (types == null) typesByName.put(name, types = new Vector<TypeInfo>());

            for (index = 0; index < types.size(); ++index) {
              TypeInfo info = (TypeInfo) types.elementAt(index);

              if (typeInfo.getTypeNamespace().equals(info.getTypeNamespace())) break;
            }
            if (index == types.size()) types.add(typeInfo);

            list = (MutableNodeList) elementsByType.get(name);

            if (list == null) elementsByType.put(name, list = new MutableNodeList());

            list.add(node);
          }

          Attr id = ((Element) node).getAttributeNode("id");

          if (id != null) elementsById.put(id.getValue(), node);

          NamedNodeMap map = ((Element) node).getAttributes();
          for (int index = 0; index < map.getLength(); ++index) {
            Attr attr = (Attr) map.item(index);

            list = (MutableNodeList) attributesByName.get(attr.getName());

            if (list == null) attributesByName.put(attr.getName(), list = new MutableNodeList());

            list.add(attr);
          }

          for (Node child = node.getFirstChild(); child != null; ) {
            if (child.getNodeType() == Node.ELEMENT_NODE) indexNodes(child);

            child = child.getNextSibling();
          }
          break;
        }
    }
  }