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.

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

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.


¿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?)


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


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

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

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

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

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.