简体   繁体   English

具有属性的XPath选择元素

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM