Obtener XML sin formato de SOAPMessage en Java

79

He configurado un SOAP WebServiceProvider en JAX-WS, pero tengo problemas para averiguar cómo obtener el XML sin formato de un objeto SOAPMessage (o cualquier nodo). Aquí hay una muestra del código que tengo ahora, y donde estoy tratando de obtener el 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?
    }
}

¿Existe una forma sencilla de obtener el XML de la solicitud original? Si hay una forma de obtener el XML sin procesar configurando un tipo diferente de proveedor (como Fuente), también estaría dispuesto a hacerlo.

Dan Lew
fuente

Respuestas:

152

Podrías intentarlo de esta manera.

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());
Smith Torsahakul
fuente
4
Esto no tiene en cuenta la codificación de caracteres
artbristol
¿Consumirá mucha memoria con algo como la construcción de objetos DOM o similares? ¿O realmente dará la cadena sin procesar de la respuesta HTTP sin analizar internamente el xml?
Ruslan
22

Si tiene una SOAPMessageo SOAPMessageContext, puede usar una Transformer, convirtiéndola en una Sourcevía 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());

Esto tendrá en cuenta la codificación, por lo que sus "caracteres especiales" no se estropearán.

Artbristol
fuente
¿Se proporciona memoria de disolución?
lospejos
12

Resulta que uno puede obtener el XML sin formato utilizando Provider <Source>, de esta manera:

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

Terminé sin necesitar esta solución, por lo que en realidad no he probado este código; es posible que necesite algunos ajustes para hacerlo bien. Pero sé que este es el camino correcto para obtener el XML sin formato de un servicio web.

(No estoy seguro de cómo hacer que esto funcione si absolutamente debe tener un objeto SOAPMessage, pero, de nuevo, si va a manejar el XML sin formato de todos modos, ¿por qué usaría un objeto de nivel superior?)

Dan Lew
fuente
Una StringWriteres una buena alternativa al ByteArrayOutputStream+ StreamResultcombinación, si desea que el XML como Stringcon la codificación correcta
artbristol
12

solo para fines de depuración, use un código de línea:

msg.writeTo(System.out);

Shahadat Hossain Khan
fuente
El OP no necesariamente está depurando en System.out (que no es necesariamente accesible de manera conveniente para un servidor web); es posible que deba enviar el XML original a través de un socket, almacenarlo en algún lugar o calcular sus estadísticas.
nanofaradio
Puede escribir fácilmente a un ByteArrayOutputStreamconvertido a String... me parece fácil
vikingsteve
7

Si necesita formatear la cadena xml a xml, intente esto:

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")));
Hari
fuente
¿Es posible elegir entre espacios y pestañas para hacer este formato? Por cierto, sé que las pestañas no están indicadas.
Philippe Gioseffi
7

Usando Transformer Factory: -

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();
    }
Sireesh Yarlagadda
fuente
3

esto funciona

 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();
usuario2900572
fuente
No se necesita explicación.
Martin Kersten
0

si tiene el código de cliente, solo necesita agregar las siguientes dos líneas para obtener la solicitud / respuesta XML. Aqui _callestaorg.apache.axis.client.Call

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

Es un hilo bastante antiguo, pero recientemente tuve un problema similar. Estaba llamando a un servicio de jabón en sentido descendente, desde un servicio de descanso, y necesitaba devolver la respuesta xml procedente del servidor en sentido descendente como está.

Entonces, terminé agregando un controlador SoapMessageContext para obtener la respuesta XML. Luego inyecté la respuesta xml en el contexto del servlet como un atributo.

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

Luego recuperé la cadena de respuesta xml en la capa de servicio.

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

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

Todavía no tuve la oportunidad de probarlo, pero este enfoque debe ser seguro para subprocesos, ya que utiliza el contexto del servlet.

Oguz Demir
fuente