【问题标题】:SOAPHandler: How to remove automatically added namespace/attribute from child elementSOAPHandler:如何从子元素中删除自动添加的命名空间/属性
【发布时间】:2026-01-01 18:35:02
【问题描述】:

我正在尝试在我的服务器上设置一个SOAPHandler 来转换这个传入的请求

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <getMachine xmlns="http://machine.soap.webservices.product.company.at/">
            <machineId>92623-15853588</machineId>
        </getMachine>
    </S:Body>
</S:Envelope>

对此请求。

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <enns1:getMachine xmlns:enns1="http://machine.soap.webservices.product.company.at/">
            <machineId>92623-15853588</machineId>
        </enns1:getMachine>
    </S:Body>
</S:Envelope>

我的 SOAPHandler 看起来像这样。

package at.company.product.webservices.soap;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPValidationHandler implements SOAPHandler<SOAPMessageContext> {

    private static final String PREFIX = "enns1";

    @Override
    public boolean handleMessage(SOAPMessageContext context) {

        System.out.println("Server : handleMessage()......");

        Boolean isRequest = (Boolean) context
                .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        // inbound
        if (!isRequest) {

            try {
                SOAPMessage soapMsg = context.getMessage();

                SOAPBody body = soapMsg.getSOAPBody();
                Iterator<SOAPElement> it = body.getChildElements();

                // Look for all body elements who have a "xmlns" attribute and
                // add a namespace prefix to it
                while (it.hasNext()) {

                    SOAPElement elem = it.next();
                    addNamespacePrefix(elem);

                    Iterator itChildren = elem.getChildElements();

                    while (itChildren.hasNext()) {
                        Object child = itChildren.next();

                        if (child instanceof SOAPElement) {
                            SOAPElement cElem = ((SOAPElement) child);

                            // TODO: Remove the namespace from the child
                            // cElem.removeNamespaceDeclaration(""); => Does not
                            // work
                        }
                    }

                }

                // tracking
                soapMsg.writeTo(System.out);

            } catch (SOAPException e) {
                System.err.println(e);
            } catch (IOException e) {
                System.err.println(e);
            }
        }

        return true;
    }

    private void addNamespacePrefix(SOAPElement elem) throws SOAPException {
        Iterator<Object> it = elem.getAllAttributes();

        QName name = new QName("xmlns");
        String value = elem.getAttributeValue(name);

        if (value != null) {
            elem.addNamespaceDeclaration(PREFIX, elem.getNamespaceURI());
            elem.removeNamespaceDeclaration("");
            elem.setPrefix(PREFIX);
        }

    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        System.out.println("Server : handleFault()......");
        return true;
    }

    @Override
    public void close(MessageContext context) {
        System.out.println("Server : close()......");
    }

    @Override
    public Set<QName> getHeaders() {
        System.out.println("Server : getHeaders()......");
        return null;
    }

}

使用 SOAPHandler 处理请求后,请求如下所示:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <enns1:getMachine xmlns:enns1="http://machine.soap.webservices.product.company.at/">
             <machineId xmlns="http://machine.soap.webservices.product.company.at/">92623-15853588</machineId>
        </enns1:getMachine>
    </S:Body>
</S:Envelope>

如您所见,我可以将命名空间前缀添加到&lt;getMachine&gt; 标记,但随后它会自动将xmlns 属性添加到子元素&lt;machineId&gt;。我该如何避免或解决这个问题?

【问题讨论】:

    标签: java soap namespaces soaphandler


    【解决方案1】:

    在玩弄了 API 之后,我想出了这个解决方案。这解决了所描述的情况。

    package at.company.product.webservices.soap;
    
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.Set;
    
    import javax.xml.namespace.QName;
    import javax.xml.soap.SOAPBody;
    import javax.xml.soap.SOAPElement;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPFault;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.ws.handler.MessageContext;
    import javax.xml.ws.handler.soap.SOAPHandler;
    import javax.xml.ws.handler.soap.SOAPMessageContext;
    import javax.xml.ws.soap.SOAPFaultException;
    
    public class SOAPValidationHandler implements SOAPHandler<SOAPMessageContext> {
    
        private static final String PREFIX = "enns1";
    
        @Override
        public boolean handleMessage(SOAPMessageContext context) {
    
    
            Boolean isRequest = (Boolean) context
                    .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    
            // for response message only, true for outbound messages, false for
            // inbound
            if (!isRequest) {
    
                try {
                    SOAPMessage soapMsg = context.getMessage();
                    SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
                    SOAPHeader soapHeader = soapEnv.getHeader();
    
                    // if no header, add one
                    if (soapHeader == null) {
                        soapHeader = soapEnv.addHeader();
                        // throw exception
                        generateSOAPErrMessage(soapMsg, "No SOAP header.");
                    }
    
                    SOAPBody body = soapMsg.getSOAPBody();
                    Iterator<SOAPElement> it = body.getChildElements();
    
                    while (it.hasNext()) {
                        SOAPElement elem = it.next();
                        addNamespacePrefix(elem);
    
    
                        Iterator itChildChildren = elem.getChildElements();
                        while (itChildChildren.hasNext()) {
                            Object obj = itChildChildren.next();
                            if ((obj instanceof SOAPElement)) {
                                SOAPElement soapElem = (SOAPElement) obj;
                                String name = soapElem.getElementName().getLocalName();
    
                                QName qName = new QName(name);
                                ((SOAPElement) obj).setElementQName(qName);
                            }
                        }
                    }
    
                    // tracking
                    soapMsg.writeTo(System.out);
    
                } catch (SOAPException e) {
                    System.err.println(e);
                } catch (IOException e) {
                    System.err.println(e);
                }
    
            }
    
            // continue other handler chain
            return true;
        }
    
        private void addNamespacePrefix(SOAPElement elem) throws SOAPException {
            Iterator<Object> it = elem.getAllAttributes();
    
            QName name = new QName("xmlns");
            String value = elem.getAttributeValue(name);
    
            if (value != null) {
                elem.addNamespaceDeclaration(PREFIX, elem.getNamespaceURI());
                elem.removeNamespaceDeclaration("");
                elem.setPrefix(PREFIX);
            }
    
        }
    
        @Override
        public boolean handleFault(SOAPMessageContext context) {
            return true;
        }
    
        @Override
        public void close(MessageContext context) {
        }
    
        @Override
        public Set<QName> getHeaders() {
            return null;
        }
    
        private void generateSOAPErrMessage(SOAPMessage msg, String reason) {
            try {
                SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
                SOAPFault soapFault = soapBody.addFault();
                soapFault.setFaultString(reason);
                throw new SOAPFaultException(soapFault);
            } catch (SOAPException e) {
            }
        }
    
    }
    

    【讨论】: