ChatGPT解决这个技术问题 Extra ChatGPT

从 Java 中的 SOAPMessage 获取原始 XML

我已经在 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?
    }
}

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


p
palacsint

你可以试试这种方式。

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

这不考虑字符编码
它会通过构造 DOM 对象等消耗大量内存吗?或者它真的会在没有内部解析 xml 的情况下从 HTTP 响应中给出原始字符串吗?
@artbristol:您可以使用 String 类的其他构造函数,即 String(out.toByteArray(),StandardCharsets.UTF_8) 来处理字符编码
a
artbristol

如果您有 SOAPMessageSOAPMessageContext,则可以使用 Transformer,通过 DOMSource 将其转换为 Source

            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());

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


提供的解决方案是否会消耗内存?
c
childno͡.de

事实证明,可以通过使用 Provider 获取原始 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;
    }
}

我最终不需要这个解决方案,所以我自己并没有真正尝试过这个代码——它可能需要一些调整才能正确。但我知道这是从 Web 服务获取原始 XML 的正确途径。

(如果您绝对必须有一个 SOAPMessage 对象,我不确定如何进行这项工作,但话又说回来,如果您要处理原始 XML,为什么要使用更高级别的对象?)


如果您希望 XML 作为具有正确编码的 StringStringWriterByteArrayOutputStream+StreamResult 组合的一个很好的替代品
S
Shahadat Hossain Khan

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

msg.writeTo(System.out);


OP 不一定要调试到 System.out(Web 服务器不一定可以方便地访问它)——他/她可能需要通过套接字发送原始 XML、将其存储在某处或计算其统计信息。
您可以轻松地写入 ByteArrayOutputStream 转换为 String... 对我来说似乎很容易
S
Sireesh Yarlagadda

使用变压器工厂:-

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

M
Michael Myers

如果您需要将 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")));

是否可以在空格和制表符之间进行选择来进行这种格式化?顺便说一句,我知道没有显示标签。
s
sygi

这行得通

 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();

无需解释。
A
ARIJIT

如果您有客户端代码,则只需添加以下两行即可获取 XML 请求/响应。这里 _callorg.apache.axis.client.Call

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

O
Oguz Demir

这是很老的线程,但最近我遇到了类似的问题。我正在从一个休息服务调用一个下游肥皂服务,我需要按原样返回来自下游服务器的 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 上下文。