Статьи

ElementList как замена для NodeList

Если вы когда-либо использовали метод Element.getElementsByTagName (), который возвращает org.w3c.dom.NodeList , у вас, вероятно, возникла одна из следующих проблем:

  • NodeList не является списком,
    поэтому вы не можете использовать полезные методы интерфейса List или класса Collections .
  • NodeList не реализует Iterable .
    Таким образом, вы не можете использовать для каждой функции цикла, добавленной в Java 5.
  • Метод добавляет все подэлементы, а не только прямые элементы
  • NodeList — это «список» Node.
    Итак, чтобы получить Элемент, вам нужно привести Node к Элементу.
  • Метод возвращает детей в неправильном порядке.
  • Нет удобного способа получить уникальный подэлемент.

Вот почему я написал
ElementList и решил разместить код в открытом доступе.

  • Реализует список, который делает его итеративным для каждого цикла
  • Включает в себя только прямой дочерний элемент
  • Метод get возвращает объекты класса Element
  • По умолчанию включены все прямые дочерние элементы
  • Сохраняет порядок дочерних элементов
  • Включает метод для получения подэлемента, когда уникальный

Если вы не хотите переходить по ссылке, вот код:

/*
 * The code of this file is in public domain.
 */
package org.xins.common.xml;

import java.util.LinkedList;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.xins.common.text.ParseException;

/**
 * An ElementList is an NodeList with the following improvements:
 * <ul><li>Implements List which make it iterable with for each loop
 * </li><li>Only includes the direct child of the element
 * </li><li>Only includes the elements
 * </li><li>By default includes all direct child elements
 * </li><li>Preserves the order of the child elements
 * </li><li>Includes a method to get the sub element when unique
 * </li></ul>
 *
 * @author <a href="mailto:[email protected]">Anthony Goubard</a>
 *
 * @since XINS 3.0
 */
public class ElementList extends LinkedList {

   /**
    * The local name of the parent element.
    */
   private String parentName;

   /**
    * The local name of the child elements or * for all elements
    */
   private String childName;

   /**
    * Creates a list with all direct child element of the given element.
    *
    * @param element
    *    the parent element, cannot be <code>null</code>.
    */
   public ElementList(Element element) {
      this(element, "*");
   }

   /**
    * Creates a list with all direct child element with a specific local name of the given element.
    *
    * @param element
    *    the parent element, cannot be <code>null</code>.
    * @param childName
    *    the local name of the direct child elements that should be added to the list, cannot be <code>null</code>.
    */
   public ElementList(Element element, String childName) {
      parentName = element.getTagName();
      this.childName = childName;
      Node child = element.getFirstChild();
      while (child != null) {
         String newChildName = child.getLocalName();
         if (newChildName == null) {
            newChildName = child.getNodeName();
         }
         if (child.getNodeType() == Node.ELEMENT_NODE &&
                 (childName.endsWith("*") || childName.equals(newChildName))) {
            add((Element) child);
         }
         child = child.getNextSibling();
      }
   }

   /**
    * Gets the unique child of this list.
    *
    * @return
    *    the sub-element of this element list, never <code>null</code>.
    *
    * @throws ParseException
    *    if no child with the specified name was found,
    *    or if more than one child with the specified name was found.
    */
   public Element getUniqueChildElement() throws ParseException {
      if (isEmpty()) {
         throw new ParseException("No \"" + childName + "\" child found in the \"" + parentName + "\" element.");
      } else if (size() > 1) {
         throw new ParseException("More than one \"" + childName + "\" children found in the \"" + parentName + "\" element.");
      }
      return get(0);
   }

   /**
    * Gets the first child of this element.
    *
    * @return
    *    the sub-element of this element, or <code>null</code> if no element is found.
    */
   public Element getFirstChildElement() {
      if (isEmpty()) {
         return null;
      }
      return get(0);
   }
}