May12
May12

Reputation: 2520

How to remove prefix and namespace in SOAPElement?

Collogues, i have cycle which create soap xml with nessesary structure (don't ask about the structure)

log.info("Body elements: ");
NodeList nodeList = body.getElementsByTagName("*") ;
for (int i = 0; i < nodeList.getLength(); i++) {
    Node node = nodeList.item(i);
    if (node.getNodeType() == Node.ELEMENT_NODE) {
        log.info(node.getNodeName());

        if (node.getNodeName().equals("ns2:request")) {
            log.info("Set namespace and prefix for " + node.getNodeName());
            SOAPElement childX = (SOAPElement) node;
            childX.removeNamespaceDeclaration(childX.getPrefix()) ;
            childX.addNamespaceDeclaration("ns3", "http://mayacomp/Generic/Ws");
            childX.setPrefix("ns3");
        }

        else {                        
            if (node.getNodeName().equals("ns2:in") ) {
                log.info("Remove namespace for  " + node.getNodeName());
                SOAPElement childX = (SOAPElement) node;
                childX.removeNamespaceDeclaration(childX.getPrefix()) ;
                childX.addNamespaceDeclaration("", "");
                childX.setPrefix("");
            }

            SOAPElement childX = (SOAPElement) node;
            childX.removeNamespaceDeclaration(childX.getPrefix()) ;
            childX.setPrefix("");
        }
    }
}

As a result I receive xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
         <in xmlns="http://mayacomp/Generic/Ws">
            <requestHeader>

My question is how to remove only xmlns="http://mayacomp/Generic/Ws" from <in> element and receive:

   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <soapenv:Body>
          <ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
             <in>
                <requestHeader>

UPDATE

I tried to config xml element:

    /*Config body elements*/
                while (itBodyElements.hasNext()) 
                {  
                  Object o = itBodyElements.next();
                  SOAPBodyElement bodyElement = (SOAPBodyElement) o;
                  log.info("Elements from 'Body' element = " + bodyElement.getLocalName() );

                  Iterator it2 = bodyElement.getChildElements();
                         while (it2.hasNext()) 
                         { 
                              Object requestElement = it2.next();
                              SOAPBodyElement bodyRequest = (SOAPBodyElement) requestElement;
                              log.info("  Elements from '"+ bodyElement.getLocalName() + "' element = " + bodyRequest.getLocalName()); 
                              log.info("  Delete namespace from IN element " + bodyRequest.getLocalName());
                              bodyRequest.removeNamespaceDeclaration(bodyRequest.getPrefix());
                              bodyRequest.setPrefix("");

                               Iterator it3 = bodyRequest.getChildElements();
                                    while (it3.hasNext())
                                    { //work with other elements

But it has not effect to 'in' element. After run i still have: <in xmlns="http://mayacomp/Generic/Ws">

UPDATE

I solved the problem by calling ws as next:

getWebServiceTemplate().marshalSendAndReceive(
                "URL",
                request,
                new WebServiceMessageCallback()
                { public void doWithMessage(WebServiceMessage message) {

                        SaajSoapMessage saajSoapMessage = (SaajSoapMessage)message;

                        SOAPMessage soapMessage = UtilsClass.createSOAPMessage(in);

                        saajSoapMessage.setSaajMessage(soapMessage);

                }

                } 
                );

Method createSOAPMessage configure soap message using javax.xml.soap library.

Upvotes: 3

Views: 16714

Answers (2)

Mike Murphy
Mike Murphy

Reputation: 1046

You could just remove the attribute using something like

    XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList nList = (NodeList)xPath.evaluate("/Envelope/Body/request/in", body, XPathConstants.NODESET);
    for (int i = 0; i < nList.getLength(); ++i) {
        Element e = (Element) nList.item(i);
        e.removeAttribute("xmlns");
    }

The following test shows that it does work.

@Test
public void removeXmlns() throws Exception {
    String xml = "" +
            "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
            "   <soapenv:Body>\n" +
            "      <ns3:request xmlns:ns3=\"http://mayacomp/Generic/Ws\">\n" +
            "         <in xmlns=\"http://mayacomp/Generic/Ws\">\n" +
            "            <requestHeader>\n" +
            "            </requestHeader>\n" +
            "         </in>\n" +
            "      </ns3:request>\n" +
            "   </soapenv:Body>\n" +
            "</soapenv:Envelope>";


    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();

    Document document = builder.parse(ResourceUtils.getFile("/soaptest.xml").getAbsolutePath());
    Element body = document.getDocumentElement();

    XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList nList = (NodeList)xPath.evaluate("/Envelope/Body/request/in", body, XPathConstants.NODESET);
    for (int i = 0; i < nList.getLength(); ++i) {
        Element e = (Element) nList.item(i);
        e.removeAttribute("xmlns");
    }
    DOMSource domSource = new DOMSource(document);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.transform(domSource, result);
    logger.info("XML IN String format is: \n" + writer.toString());     
}

The output is

2015-11-26-11-46-24[]::[main]:(demo.TestCode.removeXmlns(TestCode.java:174):174):INFO :TestCode:XML IN String format is: 
<?xml version="1.0" encoding="UTF-8" standalone="no"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns3:request xmlns:ns3="http://dfg/Ws">
         <in>
            <requestHeader>
            </requestHeader>
         </in>
      </ns3:request>
   </soapenv:Body>
</soapenv:Envelope>

Upvotes: 0

Andreas Veithen
Andreas Veithen

Reputation: 9164

If I understand the question correctly, your code gets the following XML as input:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns2:request xmlns:ns3="http://mayacomp/Generic/Ws">
         <ns2:in>
            <ns2:requestHeader>

And you want to transform it into the following XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
         <in>
            <requestHeader>

In this case, adjusting the namespace declarations and namespace prefixes is not enough because in the DOM the in and requestHeader elements will still be in the http://mayacomp/Generic/Ws namespace. That is because the namespace URI of a DOM element is determined at creation/parse time and doesn't change when namespace declarations are added or removed later. When the DOM is serialized, the serializer will automatically generate the necessary namespace declarations to make sure that the elements in the output effectively have the namespaces they had in the DOM. That is why you get xmlns="http://mayacomp/Generic/Ws" in the output, although that namespace declaration is not present in the DOM.

What you really need to do is to change the namespace URI for these elements. Unfortunately, DOM nodes don't have a setNamespaceURI method and you need to use Document.renameNode instead.

Upvotes: 0

Related Questions