在Java中从SOAPMessage获取原始XML

在Java中从SOAPMessage获取原始XML,java,soap,jax-ws,Java,Soap,Jax Ws,我已经在JAX-WS中设置了一个SOAP WebServiceProvider,但是我很难弄清楚如何从SOAPMessage(或任何节点)对象获取原始XML。下面是我现在得到的代码示例,我正试图从中获取XML: @WebServiceProvider(wsdlLocation="SoapService.wsdl") @ServiceMode(value=Service.Mode.MESSAGE) public class SoapProvider implements Provider<S

我已经在JAX-WS中设置了一个SOAP WebServiceProvider,但是我很难弄清楚如何从SOAPMessage(或任何节点)对象获取原始XML。下面是我现在得到的代码示例,我正试图从中获取XML:

@WebServiceProvider(wsdlLocation="SoapService.wsdl")
@ServiceMode(value=Service.Mode.MESSAGE)
public class SoapProvider implements Provider<SOAPMessage>
{
    public SOAPMessage invoke(SOAPMessage msg)
    {
        // How do I get the raw XML here?
    }
}
@WebServiceProvider(wsdlLocation=“SoapService.wsdl”)
@ServiceMode(值=Service.Mode.MESSAGE)
公共类SoapProvider实现提供程序
{
公共SOAPMessage调用(SOAPMessage消息)
{
//这里如何获取原始XML?
}
}

有没有一种简单的方法可以获取原始请求的XML?如果有一种方法可以通过设置不同类型的提供程序(如Source)来获取原始XML,我也愿意这样做。

事实证明,可以通过使用提供程序来获取原始XML,方法如下:

import java.io.ByteArrayOutputStream;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@ServiceMode(value=Service.Mode.PAYLOAD)
@WebServiceProvider()
public class SoapProvider implements Provider<Source>
{
    public Source invoke(Source msg)
    {
        StreamResult sr = new StreamResult();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        sr.setOutputStream(out);

        try {
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(msg, sr);

            // Use out to your heart's desire.
        }
        catch (TransformerException e) {
            e.printStackTrace();
        }    

        return msg;
    }
}
import java.io.ByteArrayOutputStream;
导入javax.xml.transform.Source;
导入javax.xml.transform.Transformer;
导入javax.xml.transform.TransformerFactory;
导入javax.xml.transform.stream.StreamResult;
导入javax.xml.ws.Provider;
导入javax.xml.ws.Service;
导入javax.xml.ws.ServiceMode;
导入javax.xml.ws.WebServiceProvider;
@ServiceMode(值=Service.Mode.PAYLOAD)
@WebServiceProvider()
公共类SoapProvider实现提供程序
{
公共源调用(源消息)
{
StreamResult sr=新的StreamResult();
ByteArrayOutputStream out=新建ByteArrayOutputStream();
高级setOutputStream(输出);
试一试{
Transformer trans=TransformerFactory.newInstance().newTransformer();
反式变换(msg,sr);
//按你的心愿使用。
}
捕获(转换异常e){
e、 printStackTrace();
}    
返回味精;
}
}
我最终不需要这个解决方案,所以我自己也没有尝试过这段代码——它可能需要一些调整才能正确。但我知道这是从web服务获取原始XML的正确途径


(如果您绝对必须拥有一个SOAPMessage对象,我不知道如何才能做到这一点,但是,如果您要以任何方式处理原始XML,为什么要使用更高级别的对象?

您可以这样尝试

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());

如果需要将xml字符串格式化为xml,请尝试以下操作:

String xmlStr = "your-xml-string";
Source xmlInput = new StreamSource(new StringReader(xmlStr));
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(xmlInput,
        new StreamResult(new FileOutputStream("response.xml")));

如果您有
SOAPMessage
SOAPMessageContext
,您可以使用
转换器
,通过
DOMSource
将其转换为

            final SOAPMessage message = messageContext.getMessage();
            final StringWriter sw = new StringWriter();

            try {
                TransformerFactory.newInstance().newTransformer().transform(
                    new DOMSource(message.getSOAPPart()),
                    new StreamResult(sw));
            } catch (TransformerException e) {
                throw new RuntimeException(e);
            }

            // Now you have the XML as a String:
            System.out.println(sw.toString());

这将考虑到编码,因此您的“特殊字符”不会被损坏。

仅出于调试目的,请使用单行代码-


msg.writeTo(系统输出)

如果您有客户机代码,那么只需添加以下两行即可获得XML请求/响应。这里的
\u call
org.apache.axis.client.call

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();

使用变压器工厂:-

public static String printSoapMessage(final SOAPMessage soapMessage) throws TransformerFactoryConfigurationError,
            TransformerConfigurationException, SOAPException, TransformerException
    {
        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        final Transformer transformer = transformerFactory.newTransformer();

        // Format it
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        final Source soapContent = soapMessage.getSOAPPart().getContent();

        final ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
        final StreamResult result = new StreamResult(streamOut);
        transformer.transform(soapContent, result);

        return streamOut.toString();
    }
这很有效

 final StringWriter sw = new StringWriter();

try {
    TransformerFactory.newInstance().newTransformer().transform(
        new DOMSource(soapResponse.getSOAPPart()),
        new StreamResult(sw));
} catch (TransformerException e) {
    throw new RuntimeException(e);
}
System.out.println(sw.toString());
return sw.toString();

这是一个非常老的线程,但最近我有一个类似的问题。我从rest服务调用了一个下游soap服务,需要按原样返回来自下游服务器的xml响应

因此,我最终添加了一个SoapMessageContext处理程序来获取XML响应。然后,我将响应xml作为属性注入servlet上下文

public boolean handleMessage(SOAPMessageContext context) {

            // Get xml response
            try {

                ServletContext servletContext =
                        ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

                SOAPMessage msg = context.getMessage();

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                msg.writeTo(out);
                String strMsg = new String(out.toByteArray());

                servletContext.setAttribute("responseXml", strMsg);

                return true;
            } catch (Exception e) {
                return false;
            }
        }
然后,我在服务层中检索了xml响应字符串

ServletContext servletContext =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

        String msg = (String) servletContext.getAttribute("responseXml");

还没有机会测试它,但这种方法必须是线程安全的,因为它使用的是servlet上下文。

这没有考虑字符编码,它会消耗大量内存来构建DOM对象之类的东西吗?或者它真的会在不内部解析xml的情况下从HTTP响应中提供原始字符串吗?
StringWriter
ByteArrayOutputStream
+
StreamResult
组合的一个很好的替代品,如果您希望xml作为
字符串
使用正确的编码,那么OP不一定要调试到System.out(Web服务器不一定可以方便地访问)--他/她可能需要通过套接字发送原始XML,将其存储在某处,或计算其统计信息。您可以轻松地通过tearrayoutputstream将
写入
字符串
转换为
字符串
…似乎很容易解决内存消耗问题?无需解释。是否可以在空格和制表符之间进行选择以执行此格式设置顺便说一句,我知道标签没有标明。