Получение необработанного XML из SOAPMessage в Java

Я настроил SOAP WebServiceProvider в JAX-WS, но не могу понять, как получить необработанный XML из объекта SOAPMessage (или любого узла). Вот образец кода, который у меня есть прямо сейчас, и где я пытаюсь получить 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 исходного запроса? Если есть способ получить необработанный XML, установив другой тип поставщика (например, Source), я бы тоже хотел это сделать.


person Dan Lew    schedule 06.02.2009    source источник


Ответы (9)


Вы могли бы попробовать таким образом.

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());
person Smith Torsahakul    schedule 29.09.2009
comment
Это не учитывает кодировку символов - person artbristol; 19.11.2013
comment
Будет ли он потреблять много памяти для чего-то вроде создания объектов DOM или чего-то подобного? Или он действительно даст необработанную строку из ответа HTTP без внутреннего анализа xml? - person Ruslan; 28.03.2016

Если у вас есть SOAPMessage или SOAPMessageContext, вы можете использовать Transformer, преобразовав его в Source через 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());

При этом будет учитываться кодировка, поэтому ваши «специальные символы» не будут искажены.

person artbristol    schedule 20.11.2013
comment
Предоставляется ли решение, потребляющее много памяти? - person lospejos; 13.07.2016

Оказывается, можно получить необработанный XML с помощью Provider ‹Source> следующим образом:

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

В итоге мне это решение не понадобилось, поэтому я сам не пробовал этот код - возможно, потребуется некоторая настройка, чтобы все исправить. Но я знаю, что это правильный путь для получения необработанного XML из веб-службы.

(Я не уверен, как заставить это работать, если вам абсолютно необходимо иметь объект SOAPMessage, но опять же, если вы все равно собираетесь обрабатывать необработанный XML, зачем вам использовать объект более высокого уровня?)

person Dan Lew    schedule 25.02.2009
comment
StringWriter - хорошая альтернатива комбинации _2 _ + _ 3_, если вы хотите, чтобы XML был String с правильной кодировкой. - person artbristol; 20.11.2013

просто для отладки используйте один строковый код -

msg.writeTo(System.out);

person Shahadat Hossain Khan    schedule 11.09.2014
comment
OP не обязательно отлаживает System.out (который не обязательно удобно доступен для веб-сервера) - ему / ей может потребоваться отправить исходный XML через сокет, сохранить его где-нибудь или вычислить его статистику. - person nanofarad; 11.09.2014
comment
Вы можете легко записать ByteArrayOutputStream преобразовать в _2 _... мне кажется легко - person vikingsteve; 17.08.2016

Если вам нужно отформатировать строку 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")));
person Hari    schedule 04.12.2010
comment
Можно ли для этого форматирования выбирать между пробелами и табуляциями? Кстати, я знаю, что вкладки не указаны. - person Philippe Gioseffi; 22.06.2018

Использование трансформаторной фабрики: -

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();
    }
person Sireesh Yarlagadda    schedule 22.06.2016

это работает

 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();
person user2900572    schedule 13.04.2017
comment
Никаких объяснений не требуется. - person Martin Kersten; 19.01.2018

если у вас есть клиентский код, вам просто нужно добавить следующие две строки, чтобы получить XML-запрос / ответ. Здесь _call это org.apache.axis.client.Call

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();
person ARIJIT    schedule 17.06.2016

Это довольно старый поток, но недавно у меня была аналогичная проблема. Я звонил в подчиненную службу мыла из службы отдыха, и мне нужно было вернуть xml-ответ, приходящий с нижестоящего сервера, как есть.

Итак, я добавил обработчик SoapMessageContext для получения ответа XML. Затем я ввел ответ xml в контекст сервлета в качестве атрибута.

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

Еще не было возможности протестировать его, но этот подход должен быть потокобезопасным, поскольку он использует контекст сервлета.

person Oguz Demir    schedule 13.08.2019