如何找到具有特定属性值的子元素
问题描述:
我习惯于C++库进行xml解析,即rapidxml和tinyxml。内置在DOM解析器中的java对我来说绝对没有意义。经过一番斗争后,我能够存储我需要的根节点,但现在我想要找到具有特定ID的标签。如何找到具有特定属性值的子元素
下面是一个示例的xml:
<?xml version="1.0" encoding="UTF-8"?>
<adventure title="Test Adventure" author="Tester">
<enemies>
<enemy id="e1" difficulty="1">Enemy1</enemy>
</enemies>
<story>
<narration id="n1" action="d1">It's adventure time!</narration>
<decision id="d1">
<description>Would you like to participate?</description>
<choice action="n2">Yes, please.</choice>
<choice action="n3">Not the slightest.</choice>
</decision>
<narration id="n2" action="end">Great choice!</narration>
<narration id="n3" action="end">Okay...</narration>
</story>
</adventure>
我有存储在Node
实例<story>
节点。从那里,我想找到具有特定ID的节点(假设'n3'节点)。
我想用这个方法:
private Node findNode(String id) {
Node node = storyNode.getFirstChild();
while (node != null) {
Element elem = (Element)node;
if (elem.getAttribute("id") == id) {
return node;
}
node = node.getNextSibling();
}
return null;
}
这将是我的方式去与C++库,但这是工作很远......我不明白为什么我要强制转换为了这么简单的任务。为什么Node
不能通过指定属性名称来获取属性。 getFirstChild()
甚至似乎不会返回第一个孩子...
我在网上找到的包装类是30深循环,甚至更难使用。为什么这很复杂?我究竟做错了什么?
答
为什么这个API是如此...真棒...会回到为什么和它是如何设计的。那么你的想法可能会比较简单。
您可以使用的功能之一是XPath实现,它被吹捧为XML的查询语言。
因此,而不是通过每个节点,每个子节点试图循环,你可以简单地使用类似//*[@id='n1']
找到与id
属性,它等于n1
(例如)的任何节点。
使用您的示例XML和下面的代码...
try {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File("Test.xml"));
Node root = doc.getDocumentElement();
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xExpress = xPath.compile("//*[@id='n1']");
NodeList nl = (NodeList)xExpress.evaluate(root, XPathConstants.NODESET);
System.out.println("Found " + nl.getLength() + " matches");
} catch (SAXException | IOException | ParserConfigurationException | XPathExpressionException ex) {
ex.printStackTrace();
}
此输出
Found 1 matches
看看XPath的一些细节
奇怪的是,这是非常相似的在.Net库中的工具,所以我假设它是基于来自标准机构的推荐,谁可能设计了解决方案,并且从来不必使用... – MadProgrammer
@Ma dProgrammer真的很疯狂。 NodeList必须迭代,但不能与迭代器一起使用,因为获取节点的唯一方法是使用'.item(index)'方法,该方法返回一个'Node',它可以*一个'元素',它继续,并继续... 我需要三个方法,一个可以抓住下一个兄弟,一个返回一个特定的子元素,或第一个,如果它被称为没有参数,第三个读取特定的属性。如果我想,我不能让这更难,但这里真的是错误的。 – Innkeeper
就我个人而言,我写了一个小库来“包装”疯狂...是的,我甚至写了一个'IterableNodeList' ...我的直觉是它是由工程师设计和编写的......非常好的论文..对于实际上不得不使用它的人来说不是那么多;) – MadProgrammer