Итерация NodeList, состоящий из некоторых тегов с тем же именем с помощью DOM
Я пытаюсь читать в XML, используя DOM в Java
<?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 :
что меня совершенно смущает. Не могли бы вы сказать, где я ошибаюсь? Количество тегов продуктов питания не определено заранее.
3 ответов
((Node) foodNode.getChildNodes().item(0)).getNodeValue()
обратите внимание, что, как вы можете ясно видеть, работа с DOM API в Java довольно болезненна. Вы смотрели на помощи jdom или dom4j?
чтобы получить подэлементы элемента, я создал класс, который заменяет NodeList:
ElementList в качестве замены для 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);
}
}
вы можете создать свой собственный узла класс и реализует типа 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 должен быть в отдельном файле.