如何在SOAPElement中去掉前缀和命名空间?

3
同事们,我有一个循环,可以创建具有必要结构的SOAP XML(不要问我关于结构的问题)。
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("");
        }
    }
}

作为结果,我收到了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>

我的问题是如何仅从<in>元素中移除xmlns="http://mayacomp/Generic/Ws"并接收:

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

更新

我试图配置XML元素:

    /*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

但是它对'in'元素没有影响。运行后,我仍然有: <in xmlns="http://mayacomp/Generic/Ws">

更新

我通过以下方式调用ws解决了这个问题:

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

                        SaajSoapMessage saajSoapMessage = (SaajSoapMessage)message;

                        SOAPMessage soapMessage = UtilsClass.createSOAPMessage(in);

                        saajSoapMessage.setSaajMessage(soapMessage);

                }

                } 
                );

方法createSOAPMessage使用javax.xml.soap库配置SOAP消息。


你知道这两个 XML 片段意思是不同的吧?在第一个片段中,<requestHeader> 将位于命名空间 http://mayacomp/Generic/Ws 中。而在第二个片段中,它将位于默认命名空间中(即之前的默认命名空间)。 - ParkerHalo
2个回答

0

您可以使用类似以下的方式来删除属性

    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");
    }

以下测试显示它确实有效。
@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());     
}

输出结果为

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>

1
这样做不起作用,因为在DOM中,元素仍然位于“http://mayacomp/Generic/Ws”命名空间中。 - Andreas Veithen
示例传入的 XML 具有 <ns3:request xmlns:ns3="" rel = "nofollow noreferrer">http://mayacomp/Generic/Ws"> 和 <in xmlns="http://mayacomp/Generic/Ws">。问题是如何删除第二个命名空间 xmlns,这就是我的代码示例所做的。 - Mike Murphy
您正在使用不带命名空间的解析,但是 OP 使用 SAAJ,它始终使用命名空间感知解析器处理消息。 - Andreas Veithen
那我可能误解了问题,没有看到关于SAAJ的任何内容。只是回答了我认为的问题。 - Mike Murphy
当然,OP提供的代码中有特定于SAAJ的方法。请仔细查看。 - Andreas Veithen
显示剩余2条评论

0

如果我理解问题正确,您的代码将以下XML作为输入:

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

而你想将它转换成以下的XML:

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

在这种情况下,调整命名空间声明和命名空间前缀是不够的,因为在 DOM 中,inrequestHeader 元素仍然位于 http://mayacomp/Generic/Ws 命名空间中。这是因为 DOM 元素的命名空间 URI 是在创建/解析时确定的,并且在稍后添加或删除命名空间声明时不会更改。当序列化 DOM 时,序列化器将自动生成必要的命名空间声明,以确保输出中的元素实际上具有它们在 DOM 中具有的命名空间。这就是为什么您在输出中得到 xmlns="http://mayacomp/Generic/Ws",尽管该命名空间声明在 DOM 中不存在。
你真正需要做的是更改这些元素的命名空间 URI。不幸的是,DOM 节点没有 setNamespaceURI 方法,您需要使用 Document.renameNode 来代替。

Andreas Veithen,我添加了更新。你能看一下吗? - May12
你的更新没有考虑到我在答案中解释的内容,所以它仍然不能正常工作并不令人惊讶。 - Andreas Veithen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接