Отримання 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.