【问题标题】:Iterating a NodeList consisting some tags with same name using DOM使用 DOM 迭代包含一些具有相同名称的标签的 NodeList
【发布时间】:2012-08-21 09:32:45
【问题描述】:

我正在尝试使用 Java 中的 DOM 读取 XML

<?xml version="1.0"?>
<record>
<user>
    <name>Leo</name>
    <email>****@****.com</email>
        <food-list>
            <food>Hamburgers</food>
            <food>Fish</food>
        </food-list>
</user>
</record>

我目前的解决方案是

    for (int userNumber = 0; userNumber < masterList.getLength(); userNumber++) {

           Node singleUserEntry = masterList.item(userNumber);
           if (singleUserEntry.getNodeType() == Node.ELEMENT_NODE) {

              org.w3c.dom.Element userEntryElement = (org.w3c.dom.Element) singleUserEntry;



              System.out.println("name : " + getTagValue("name", userEntryElement));
              System.out.println("email : " +getTagValue("email", userEntryElement));
              NodeList foodList = userEntryElement.getElementsByTagName("food-list").item(0).getChildNodes();
              for(int i = 0; i < foodList.getLength(); i++){
                  Node foodNode = foodList.item(i);
                  System.out.println("food : " + foodNode.getNodeValue());
              }

private static String getTagValue(String sTag, org.w3c.dom.Element eElement) {
     NodeList nlList =  eElement.getElementsByTagName(sTag).item(0).getChildNodes();
     Node nValue = (Node) nlList.item(0);
     return nValue.getNodeValue();

现在的输出是

name : Leo 
email : ******@*****.com
food :          
food : null
food :          
food : null
food : 

这让我很困惑。你能告诉我哪里错了吗?食物标签的数量没有预先定义。

【问题讨论】:

  • 你能在你的循环中检查foodNode.getNodeType()吗?
  • NodeList foodList = userEntryElement.getElementsByTagName("food-list").getChildNodes();和节点 foodNode = foodList.item(i); if(fooNode.getNodeType() == Node.ELEMENT_NODE) { 元素 userEntryElement = (Element) foodNode ; foodNode.getNodeValue()}
  • @O.R.Mapper 如果我在打印之前在 for 循环中检查foodNode.getNodeType == Node.Element_Node,我会得到两个空输出
  • @Nambari 你能告诉我你为什么要重新分配 userEntryElement 吗?
  • @YankeeWhiskey 试试((Node) foodNode.getChildNodes().item(0)).getNodeValue()

标签: java xml dom tags loops


【解决方案1】:

您可以创建自己的NodeList 类并实现Iterable

public class NodeList<T extends Node> extends JavaScriptObject implements Iterable<T> {

  protected NodeList() {
  }

  public final native T getItem(int index) /*-{
    return this[index];
  }-*/;

  public final native int getLength() /*-{
    return this.length;
  }-*/;

  @Override
  final public Iterator<T> iterator() {
    return new NodeIterator<T>(this);
  }
}

public class NodeIterator<T extends Node> implements Iterator<T> {
  private int cursor = 0;
  private NodeList<T> nodeList;

  public NodeIterator(NodeList<T> nodeList) {
    this.nodeList = nodeList;
  }

  @Override
  public boolean hasNext() {
    return cursor < nodeList.getLength();
  }

  @Override
  public T next() {
    if (hasNext()) {
      return nodeList.getItem(cursor++);
    }
    throw new NoSuchElementException();
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }
}

注意: NodeIterator 需要在单独的文件中。

【讨论】:

    【解决方案2】:

    为了获取元素的子元素,我创建了一个替换 NodeList 的类:

    ElementList as Replacement for NodeList

    请注意,代码是公共领域的。

    /*
     * 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:
    *
    
        Implements List which make it iterable with for each loop *
        Only includes the direct child of the element *
        Only includes the elements *
        By default includes all direct child elements *
        Preserves the order of the child elements *
        Includes a method to get the sub element when unique * 
    
    
    *
     * @author Anthony Goubard
    *
     * @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 null.
        */
       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 null.
        * @param childName
        *    the local name of the direct child elements that should be added to the list, cannot be null.
        */
       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 null.
        *
        * @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 null if no element is found.
        */
       public Element getFirstChildElement() {
          if (isEmpty()) {
             return null;
          }
          return get(0);
       }
    }
    

    【讨论】:

      【解决方案3】:
      ((Node) foodNode.getChildNodes().item(0)).getNodeValue()
      

      请注意,您可以清楚地看到,在 Java 中处理 DOM API 非常痛苦。你看过JDOMdom4j吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-11
        • 1970-01-01
        • 2011-02-04
        • 2017-02-28
        • 1970-01-01
        • 1970-01-01
        • 2011-09-25
        • 1970-01-01
        相关资源
        最近更新 更多