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

79

Я установил 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), я бы тоже хотел это сделать.

Дэн Лью
источник

Ответы:

152

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

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());
Кузнец Торсахакул
источник
4
Это не учитывает кодировку символов
artbristol
Будет ли он потреблять много памяти с помощью чего-то вроде построения объектов DOM или чего-то подобного? Или он действительно выдаст необработанную строку из HTTP-ответа без внутреннего синтаксического анализа xml?
Руслан
22

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

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

artbristol
источник
Предоставляется ли решение, потребляющее много памяти?
lospejos
12

Оказывается, можно получить необработанный 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, зачем вам использовать объект более высокого уровня?)

Дэн Лью
источник
A StringWriter- хорошая альтернатива комбинации ByteArrayOutputStream+ StreamResult, если вы хотите, чтобы XML был Stringс правильной кодировкой
artbristol
12

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

msg.writeTo(System.out);

Шахадат Хосейн Хан
источник
OP не обязательно отлаживает System.out (что не всегда удобно для веб-сервера) - ему / ей может потребоваться отправить исходный XML через сокет, сохранить его где-нибудь или вычислить его статистику.
нанофарад
Вы можете легко написать для ByteArrayOutputStreamобращенного в String... мне это кажется легким
vikingsteve
7

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

Использование 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

это работает

 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();
user2900572
источник
Никаких объяснений не требуется.
Мартин Керстен
0

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

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();
АРИДЖИТ
источник
0

Это довольно старый поток, но недавно у меня была аналогичная проблема. Я звонил в подчиненную службу мыла из службы отдыха, и мне нужно было вернуть 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");

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

Огуз Демир
источник