0

I have a SOAP message as as string which looks like:

 String testMsg = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\"><soap:Header>Some Header stuff</soap:Header><soap:Body>Some Body Stuff</soap:Body></soap:Envelope>";

Then it goes to XPath but can't find a node (came as null) to set text value

    Document doc = convertStringToDocument(testMsg);
    XPath xpath = XPathFactory.newInstance().newXPath();

    String expression = "//soap:Envelope/soap:Body";
    Node node = (Node) xpath.evaluate(expression, doc, XPathConstants.NODE);

    // Set the node content
    node.setTextContent("Body was removed");

I try to convert it to XML document using method below

private static Document convertStringToDocument(String xmlStr) {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);

    try
    {
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(xmlStr));
        Document doc = builder.parse(is);

        return doc;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

Any thoughts?

JackTheKnife
  • 3,795
  • 8
  • 57
  • 117
  • Possible duplicate of https://stackoverflow.com/questions/6390339/how-to-query-xml-using-namespaces-in-java-with-xpath. – VGR Mar 21 '18 at 18:14

2 Answers2

1

You definitely should redirect your question to IDE debugger. For me such code snippet works properly. For example, I can output text inside Header tags like so

System.out.println(
        doc.getElementsByTagNameNS("http://www.w3.org/2003/05/soap-envelope", "Header")
        .item(0).getTextContent());

It outputs expected Some Header stuff. In your case I think you'd printed Document instance itself and saw result like [#document: null] which confused you. But the truth is that the object exist.

UPDATE You forget to let XPath be aware of your namespace. This will do that you want.

XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {

    @Override
    public Iterator getPrefixes(String namespaceURI) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getPrefix(String namespaceURI) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getNamespaceURI(String prefix) {
        if ("soap".equals(prefix)) {
            return "http://www.w3.org/2003/05/soap-envelope";
        }
        return null;
    }
});

String expression = "/soap:Envelope/soap:Body";
Node node = (Node) xpath.compile(expression).evaluate(doc, XPathConstants.NODE);
node.setTextContent("Body was removed");

Hope it helps!

Sergey Prokofiev
  • 1,815
  • 1
  • 12
  • 21
  • Exactly - I see `[#document: null]` but then that document cannot be used with XPath as it came as null pointer – JackTheKnife Mar 21 '18 at 13:34
  • @JackTheKnife, update your question with code snippet which is not working for you. For now - you're not getting `null`, you have object instance as expected. Also as you can see from my answer it's perfectly navigable using traditional DOM API. – Sergey Prokofiev Mar 21 '18 at 14:05
  • OK, my question was updated to current state based on your answer – JackTheKnife Mar 21 '18 at 14:32
0

Other solution is to set

factory.setNamespaceAware(false);

and then update XPath code to

String expression = "/Envelope/Body";
Node node = (Node) xpath.compile(expression).evaluate(doc, XPathConstants.NODE);

Hope it will help somebody else.

JackTheKnife
  • 3,795
  • 8
  • 57
  • 117