Запрос XPath в Java не возвращает ни одного элемента - PullRequest
0 голосов
/ 12 февраля 2019

Я работаю над веб-сервисом, который использует SOAP в качестве протокола связи: я достигаю этого с помощью 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, ничего не возвращает, в то время как другие инструменты (как этот ) правильно вычисляет выражение и возвращает что-то.Единственное выражение XPath, которое корректно оценивается в Java, - это // *, больше ничего.Чего мне не хватает?

РЕДАКТИРОВАТЬ: После предложения @ Wisthler теперь проверяется XPath, но он не может что-то вернуть.Прикрепите скриншот того, что происходит сейчас: посмотрите, как переменная узлов (которая должна содержать NodesList), если я правильно понял, пустая

enter image description here

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

В дополнение к ответу @ 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!

0 голосов
/ 12 февраля 2019

Я знаю, что в прошлый раз, когда я играл с XPath в java, у меня были проблемы с пространствами имен, и мне пришлось добавить namespaceContext, чтобы он работал.

вам нужно "зарегистрировать" пространство имен soapenv, если вы хотите его использоватьв XPath.Ниже вы можете найти то, что я сделал тогда.Вероятно, не на 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/)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...