У меня есть XML, который выглядит примерно так:
<project type="mankind">
<suggestion>Build the enterprise</suggestion>
<suggestion>Learn Esperanto</suggestion>
<problem>Solve world hunger</suggestion>
<discussion>Do Vulcans exist</discussion>
</project>
Я хочу использовать XPath, чтобы узнать имена элементов второго уровня (могут быть элементы, которые я не буду знать заранее) с помощью Java. Это код, который я пробовал:
public NodeList xpath2NodeList(Document doc, String xPathString) throws XPathExpressionException {
XPath xpath = XPathFactory.newInstance().newXPath();
MagicNamespaceContext nsc = new MagicNamespaceContext();
xpath.setNamespaceContext(nsc);
Object exprResult = xpath.evaluate(xPathString, doc, XPathConstants.NODESET);
return (NodeList) exprResult;
}
Мой XPath is /project/*/name()
. Я получаю сообщение об ошибке:
javax.xml.transform.TransformerException: Неизвестный nodetype: name
Запрос типа /project/suggestion
работает так, как ожидалось. Что мне не хватает? Я хотел бы получить список с именами тегов.
Java6 (не спрашивайте).
Я думаю, что ваша реализация поддерживает только XPath 1.0. Если бы это было так, то работало бы только следующее:
"name(/project/*)"
Причиной этого является то, что в модели XPath 1.0 вы не можете использовать функции (например, name()
) как шаг в выражении пути. Ваш код генерирует исключение, и в этом случае процессор ошибочно использует ваше name()
функции name()
для теста неизвестного узла (например, comment()
). Но нет ничего плохого в использовании выражения пути в качестве аргумента функции name()
.
К сожалению, если функция XPath 1.0, которая может обрабатывать только один узел в качестве аргумента, задается последовательность узлов, используется только первая. Поэтому, скорее всего, вы получите только первое имя элемента.
Возможность управлять XPath 1.0 очень ограничена, и зачастую самый простой способ обойти такие проблемы - достичь языка более высокого уровня, который использует XPath в качестве языка запросов (в вашем случае Java). Или по-другому: напишите выражение XPath, чтобы получить все соответствующие узлы и перебрать результат, возвращая имена элементов в Java.
С XPath 2.0 ваш внутренний запрос будет в порядке. Также см. Этот связанный вопрос.
NodeList
? Можете ли вы написать разные методы, один для поиска узлов, а другой для строк?
Ниже код может ответить на ваш оригинальный вопрос.
package com.example.xpath;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XPathReader {
static XPath xPath = XPathFactory.newInstance().newXPath();
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream(new File("c:/mankind.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPathExpression expr = xPath.compile("//project/*");
NodeList list= (NodeList) expr.evaluate(xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
System.out.println(node.getNodeName() + "=" + node.getTextContent());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
}
Предполагая, что ввод исправлен (разрешите голод в мире), код должен печатать:
предложение = создать предприятие
предложение = Узнать эсперанто
проблема = Решите голод в мире
обсуждение = Существуют ли вулканы