[英]XPath select element with an attribute
I have a xml file which looks like: 我有一个xml文件,看起来像:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<alarm-response-list xmlns="http://www.ca.com/spectrum/restful/schema/response"
error="EndOfResults" throttle="277" total-alarms="288">
<alarm-responses>
<alarm id="53689bf8-6cc8-1003-0060-008010186429">
<attribute id="0x11f4a" error="NoSuchAttribute" />
<attribute id="0x12b4c">UPS DIAGNOSTIC TEST FAILED</attribute>
<attribute id="0x10b5a">IDG860237, SL3-PL4, US, SapNr=70195637,</attribute>
</alarm>
<alarm id="536b8c9a-28b3-1008-0060-008010186429">
<attribute id="0x11f4a" error="NoSuchAttribute" />
<attribute id="0x12b4c">DEVICE IN MAINTENANCE MODE</attribute>
<attribute id="0x10b5a">IDG860237, SL3-PL4, US, SapNr=70195637,</attribute>
</alarm>
</alarm-responses>
</alarm-response-list>
There a lot of these alarms. 这些警报很多。 Now I want save for every alarm tag the attribute with the id = 0x10b5a in a String. 现在,我想为每个警报标签在字符串中保存id = 0x10b5a的属性。 But I haven't a great clue. 但是我没有什么好头绪。 In my way it doesn't do it. 以我的方式,它没有做到。 I get only showed the expression. 我只显示了表情。
My idea: 我的点子:
FileInputStream file = new FileInputStream(
new File(
"alarms.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("*************************");
String expression = "/alarm-responses/alarm/attribute[@id='0x10b5a'] ";
System.out.println(expression);
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(
xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getFirstChild()
.getNodeValue());
}
There are several different problems here that are interacting to mean that your XPath expression doesn't match anything. 这里有几个不同的问题正在相互作用,这意味着您的XPath表达式不匹配任何内容。 Firstly the alarm-responses
element isn't the root of the document - you need an extra step on the front of the path to select the alarm-response-list
element. 首先, alarm-responses
元素不是文档的根-您需要在路径的前面执行一个额外的步骤来选择alarm-response-list
元素。 But more importantly you have namespace issues. 但更重要的是,您有名称空间问题。
XPath only works when the XML has been parsed with namespaces enabled, which for some reason is not the default for DocumentBuilderFactory
. XPath仅在解析XML且启用了名称空间后才起作用,由于某种原因,这不是DocumentBuilderFactory
的默认值。 You need to enable namespaces before you do newDocumentBuilder
. 在执行newDocumentBuilder
之前,需要启用名称空间。
Now your XML document has xmlns="http://www.ca.com/spectrum/restful/schema/response"
, which puts all the elements in this namespace, but unprefixed node names in an XPath expression always refer to nodes that are not in a namespace. 现在,您的XML文档具有xmlns="http://www.ca.com/spectrum/restful/schema/response"
,它将所有元素都放在此命名空间中,但是XPath表达式中未前缀的节点名称始终引用的是不在命名空间中。 In order to match namespaced nodes you need to bind a prefix to the namespace URI and then use prefixed names in the path. 为了匹配命名空间节点,您需要将前缀绑定到命名空间URI,然后在路径中使用前缀名称。
For javax.xml.xpath
this is done using a NamespaceContext
, but annoyingly there is no default implementation of this interface available by default in the Java core library. 对于javax.xml.xpath
这是使用NamespaceContext
完成的,但令人讨厌的是,Java核心库中默认没有此接口的默认实现。 There is a SimpleNamespaceContext implementation available as part of Spring, or it's fairly simple to write your own. Spring提供了一个SimpleNamespaceContext实现,或者编写自己的实现也很简单。 Using the Spring class: 使用Spring类:
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
// enable namespaces
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
// Set up the namespace context
SimpleNamespaceContext ctx = new SimpleNamespaceContext();
ctx.bindNamespaceUri("ca", "http://www.ca.com/spectrum/restful/schema/response");
xPath.setNamespaceContext(ctx);
System.out.println("*************************");
// corrected expression
String expression = "/ca:alarm-response-list/ca:alarm-responses/ca:alarm/ca:attribute[@id='0x10b5a']";
System.out.println(expression);
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(
xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getTextContent());
}
Note also how I'm using getTextContent()
to get the text under each matched element. 还要注意我如何使用getTextContent()
获取每个匹配元素下的文本。 The getNodeValue()
method always returns null
for element nodes. getNodeValue()
方法始终为元素节点返回null
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.