Отримання RAW-файлу XML із SOAPMessage на Java


79

Я встановив SOAP WebServiceProvider у JAX-WS, але у мене виникають проблеми з тим, як отримати необроблений XML із об'єкта SOAPMessage (або будь-якого Node). Ось зразок коду, який я отримав зараз, і де я намагаюся отримати 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, перетворивши його на Sourcevia 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());

Це врахує кодування, тому ваші "спеціальні символи" не будуть зіпсовані.


Чи передбачає це рішення для споживання пам'яті?
— lospejos

12

Виявляється, можна отримати необроблений 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;
    }
}

У підсумку мені не знадобилося це рішення, тому я насправді сам не пробував цей код - можливо, йому знадобиться трохи налаштувати, щоб отримати право. Але я знаю, що це правильний шлях, щоб отримати необроблений XML з веб-служби.

(Я не впевнений, як змусити це працювати, якщо у вас обов’язково повинен бути об’єкт SOAPMessage, але знову ж таки, якщо ви все одно збираєтеся обробляти необроблений XML, навіщо вам використовувати об’єкт вищого рівня?)


A StringWriter- хороша альтернатива комбінації ByteArrayOutputStream+ StreamResult, якщо ви хочете XML як a 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")));

Чи можна вибирати між пробілами та вкладками для цього форматування? До речі, я знаю, що вкладки не вказані.
— Філіпп Джозеффі,

7

Використання заводу трансформаторів: -

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

Пояснень не потрібно.
— Мартін Керстен

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

Ще не мав можливості перевірити, але цей підхід повинен бути безпечним для потоку, оскільки він використовує контекст сервлету.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.