Lấy XML thô từ SOAPMessage trong Java


79

Tôi đã thiết lập SOAP WebServiceProvider trong JAX-WS, nhưng tôi gặp khó khăn khi tìm cách lấy XML thô từ đối tượng SOAPMessage (hoặc bất kỳ Node nào). Đây là một mẫu mã mà tôi có ngay bây giờ và nơi tôi đang cố lấy 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?
    }
}

Có cách nào đơn giản để lấy XML của yêu cầu ban đầu không? Nếu có cách để lấy XML thô bằng cách thiết lập một loại Nhà cung cấp khác (chẳng hạn như Nguồn), tôi cũng sẵn lòng làm điều đó.

Câu trả lời:


152

Bạn có thể thử theo cách này.

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());

4
Đây không mất mã hóa ký tự vào tài khoản
artbristol

Nó sẽ tiêu tốn nhiều bộ nhớ với một cái gì đó như xây dựng các đối tượng DOM hoặc tương tự? Hay nó sẽ thực sự cung cấp chuỗi thô từ phản hồi HTTP mà không cần phân tích cú pháp nội bộ xml?
Ruslan

22

Nếu bạn có SOAPMessagehoặc SOAPMessageContext, bạn có thể sử dụng a Transformer, bằng cách chuyển đổi nó thành Sourcequa 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());

Điều này sẽ tính đến mã hóa, vì vậy "các ký tự đặc biệt" của bạn sẽ không bị sai lệch.


Cung cấp bộ nhớ giải phóng có tốn không?
lospejos

12

Hóa ra người ta có thể lấy XML thô bằng cách sử dụng Nhà cung cấp <Nguồn>, theo cách này:

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

Tôi đã kết thúc không cần giải pháp này, vì vậy tôi chưa thực sự tự mình thử mã này - nó có thể cần một số điều chỉnh để đúng. Nhưng tôi biết đây là con đường đúng đắn để đi xuống để lấy XML thô từ một dịch vụ web.

(Tôi không chắc làm thế nào để làm cho điều này hoạt động nếu bạn nhất thiết phải có một đối tượng SOAPMessage, nhưng một lần nữa, nếu bạn đang xử lý XML thô, tại sao bạn lại sử dụng một đối tượng cấp cao hơn?)


Một StringWriterlà một lựa chọn tốt để các ByteArrayOutputStream+ StreamResultkết hợp, nếu bạn muốn XML như một Stringvới bảng mã đúng
artbristol

12

chỉ cho mục đích gỡ lỗi, hãy sử dụng một mã dòng -

msg.writeTo(System.out);


OP không nhất thiết phải gỡ lỗi cho System.out (không nhất thiết phải truy cập thuận tiện cho máy chủ web) - anh ấy / cô ấy có thể cần gửi XML gốc qua một socket, lưu trữ nó ở đâu đó hoặc tính toán số liệu thống kê của nó.
nanofarad

Bạn có thể dễ dàng viết thư cho một ByteArrayOutputStreamchuyển đổi để String... có vẻ dễ dàng với tôi
vikingsteve

7

Nếu bạn cần định dạng chuỗi xml thành xml, hãy thử cách này:

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

Có thể chọn giữa khoảng trắng và tab để thực hiện định dạng này không? BTW, tôi biết các tab không được chỉ định.
Philippe Gioseffi

7

Sử dụng nhà máy biến áp: -

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

những công việc này

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

Không cần giải thích.
Martin Kersten

0

nếu bạn có mã khách hàng thì bạn chỉ cần thêm hai dòng sau để nhận được yêu cầu / phản hồi XML. Đây _callorg.apache.axis.client.Call

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();

0

Nó là chủ đề khá cũ nhưng gần đây tôi đã gặp sự cố tương tự. Tôi đang gọi một dịch vụ xà phòng hạ lưu, từ một dịch vụ nghỉ ngơi và tôi cần trả lại phản hồi xml đến từ máy chủ hạ lưu.

Vì vậy, tôi đã kết thúc việc thêm một trình xử lý SoapMessageContext để nhận phản hồi XML. Sau đó, tôi đã đưa phản hồi xml vào ngữ cảnh servlet như một thuộc tính.

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

Sau đó, tôi đã truy xuất chuỗi phản hồi xml trong lớp dịch vụ.

ServletContext servletContext =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

        String msg = (String) servletContext.getAttribute("responseXml");

Chưa có cơ hội để kiểm tra nó nhưng cách tiếp cận này phải an toàn cho luồng vì nó đang sử dụng ngữ cảnh servlet.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.