Java中的XPath查询未返回任何元素

时间:2019-02-12 13:49:02

标签: java xml web-services xpath soap

我正在使用SOAP作为通信协议的Web服务:我通过使用Spring Boot和Spring WS来实现这一点。
有时,可能需要通过请求的标头发送一些信息,并且希望能够通过XPath表达式恢复该信息。
这是我到目前为止所做的:

        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        WebServiceMessage message = messageContext.getRequest();

        Source s = messageContext.getRequest().getPayloadSource();
        messageContext.getRequest().writeTo(buffer);
        String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
        System.out.println(payload);
        InputStream is = new ByteArrayInputStream(payload.getBytes());

在以下代码片段中,我读取了后端接收的整个请求。然后,我以前所做的就是将所有这些转换到一个SOAPHeader对象中,该对象保存了我想要的一切。。。除了我根本无法进行任何XPath查询以及我真正需要的元素之外在树上。
因此,我决定以以下方式继续该代码段

        //-------
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new java.io.ByteArrayInputStream(payload.getBytes()));
        XPath xpath = XPathFactory.newInstance().newXPath();

现在,这是我发送的请求的一个示例

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:it="it.niuma.mscsoapws.ws">
   <soapenv:Header>
       <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
       <wsse:UsernameToken wsu:Id="UsernameToken-3967AEB46D733EF6E2154990461080350">
       <wsse:Username>TAVI</wsse:Username>
       <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
       <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">pUn8VjdpVaIamSAIwXEeXg==</wsse:Nonce>
       <wsu:Created>2019-02-11T17:03:30.803Z</wsu:Created>
       </wsse:UsernameToken></wsse:Security>
  </soapenv:Header>
   <soapenv:Body>
      <it:getPOrderRequest>
         <it:poNumber>2197111225-F03292</it:poNumber>
      </it:getPOrderRequest>
   </soapenv:Body>
</soapenv:Envelope>

我要推断的是soapenv:Header内部的整个部分,因此我使用以下XPath表达式:

        XPathExpression expr = xpath.compile("//*//soapenv:Header");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) result;
        for (int i = 0; i < nodes.getLength(); i++) {
            Node currentItem = nodes.item(i);
            System.out.println("found node -> " + currentItem.getLocalName() + " (namespace: " + currentItem.getNamespaceURI() + ")");
        }

这是我的问题:XPath表达式在Java端不返回任何内容,而其他工具(如this one)则正确地计算了该表达式并返回了一些内容。 在Java中唯一可以正确求值的XPath表达式是// *,仅此而已。 我想念什么?

编辑:在@Wisthler的建议之后,现在对XPath进行了评估,但是它无法返回任何内容。附上现在发生的情况的屏幕截图:如果我理解正确,请查看节点变量(应包含NodesList)如何为空

enter image description here

2 个答案:

答案 0 :(得分:0)

我知道上一次我在Java中使用XPath时遇到了名称空间的麻烦,必须添加一个namespaceNameContext使其起作用。

如果要在XPath中使用soapenv名称空间,则需要“注册”它。 您可以在下面找到我当时所做的事情。可能不是100%干净,但仍可能为您提供帮助

    xpath.setNamespaceContext(new NamespaceContext() {
        @Override
        public String getNamespaceURI(String prefix) {
            if("soapenv".equals(prefix)){
                return "http://schemas.xmlsoap.org/soap/envelope/";
            }else{
                return null;
            }
        }

        @Override
        public String getPrefix(String namespaceURI) {
            return null;
        }

        @Override
        public Iterator getPrefixes(String namespaceURI) {
            return null;
        }
    });

编辑:用我对代码的修复进行了测试,这是您期望看到的吗?

found node -> Header (namespace: http://schemas.xmlsoap.org/soap/envelope/)

答案 1 :(得分:0)

除了@Wisthler的回答,这是使所有内容正常工作的唯一的代码行

        factory.setNamespaceAware(true);

整个工作代码是

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new java.io.ByteArrayInputStream(payload.getBytes()));
        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new NamespaceContext() {
            @Override
            public String getNamespaceURI(String prefix) {
                if("soapenv".equals(prefix)){
                    return "http://schemas.xmlsoap.org/soap/envelope/";
                }else{
                    return null;
                }
            }

            @Override
            public String getPrefix(String namespaceURI) {
                return null;
            }

            @Override
            public Iterator getPrefixes(String namespaceURI) {
                return null;
            }
        });
        XPathExpression expr = xpath.compile("//soapenv:Envelope//soapenv:Header//text()[normalize-space()]");
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) result;

谢谢@Wisthler!