java 使用 DOM 迭代包含一些同名标签的 NodeList

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12132776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:43:19  来源:igfitidea点击:

Iterating a NodeList consisting some tags with same name using DOM

javaxmldomtagsloops

提问by YankeeWhiskey

I'm trying to read in an XML using DOM in Java

我正在尝试使用 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>

My current solution is

我目前的解决方案是

    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();

And the output now is

现在的输出是

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

Which quite confuses me. Could you tell me where I'm wrong? The number of food tags is not pre-defined.

这让我很困惑。你能告诉我我错在哪里吗?食品标签的数量不是预先定义的。

采纳答案by oldrinb

((Node) foodNode.getChildNodes().item(0)).getNodeValue()

Note that, as you can clearly see, dealing with the DOM API in Java is pretty painful. Have you looked at JDOMor dom4j?

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

回答by Anthony

To get the sub elements of an element I've created a class that replace NodeList:

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

ElementList as Replacement for NodeList

ElementList 作为 NodeList 的替代品

Note that the code is public domain.

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

/*
 * 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);
   }
}

回答by andirady

You can create your own NodeListclass and implements Iterable.

您可以创建自己的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();
  }
}

NOTE:NodeIterator needs to be in separate file.

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