21

如果肥皂信封已被删除,JAXB 只能解组 XML。但是,我试图解组的 SOAP 响应在肥皂信封上有其名称空间声明。如果我删除肥皂信封,命名空间声明也将被删除。因此,标签的前缀将指代无。这会导致 JAXB 引发错误。如果命名空间是在 SOAP 信封上声明的,如何使用 JAXB 解组 SOAP 响应?

我需要解组的 XML 的类似示例如下:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com/">
    <soapenv:Body>
        <ns:getNumberResponse>
            <number>123456789</number>
        </ns:getNumberResponse>
    </soapenv:Body>
</soapenv:Envelope>

如果我取下肥皂信封,会发生以下情况:

<ns:getNumberResponse>
    <number>123456789</number>
</ns:getNumberResponse>

如果我删除了肥皂信封,命名空间声明也将消失。JAXB 将无法解组上述 xml,因为缺少前缀“ns”的命名空间定义。因此,它将返回一条"The prefix "ns" for element "ns:getNumberResponse" is not bound."错误消息。我如何解决它?

请注意,我使用的是 JDK 1.5。我不确定在 JDK 1.6 中是否有办法解决这个问题。我能够使用 JAXB,因为我下载了使用 JAXB 所需的 jar。

4

2 回答 2

42

您可以使用 StAX 解析器来解析 SOAP 消息,然后前进XMLStreamReadergetNumberResponse元素并使用采用类参数的 unmarshal 方法。StAX 解析器包含在 Java SE 6 中,但您需要为 Java SE 5 下载一个。Woodstox是一种流行的 StAX 解析器。

回复

package forum11465653;

public class Response {

    private long number;

    public long getNumber() {
        return number;
    }

    public void setNumber(long number) {
        this.number = number;
    }

}

演示

一个XMLStreamReader有一个NamespaceContext。知道当前级别的NamespaceContext所有活动命名空间声明。您的 JAXB (JSR-222) 实现将能够利用它来获取必要的信息。

package forum11465653;

import java.io.FileReader;
import javax.xml.bind.*;
import javax.xml.stream.*;

public class Demo {

    public static void main(String[] args) throws Exception{
        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("src/forum11465653/input.xml"));
        xsr.nextTag(); // Advance to Envelope tag
        xsr.nextTag(); // Advance to Body tag
        xsr.nextTag(); // Advance to getNumberResponse tag
        System.out.println(xsr.getNamespaceContext().getNamespaceURI("ns"));

        JAXBContext jc = JAXBContext.newInstance(Response.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBElement<Response> je = unmarshaller.unmarshal(xsr, Response.class);
        System.out.println(je.getName());
        System.out.println(je.getValue());
    }

}

输出

http://example.com/
{http://example.com/}getNumberResponse
forum11465653.Response@781f6226
于 2012-07-13T09:11:06.320 回答
16

您可以使用 DOM 解析器解析整个 SOAP 消息,该解析器将能够在解析时解析所有名称空间。然后从生成的 DOM 树中提取您需要的元素并将其传递给解组器。

DomDemo

package forum11465653;

import java.io.File;
import javax.xml.bind.*;
import javax.xml.parsers.*;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.*;

public class DomDemo {

    public static void main(String[] args) throws Exception{
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document d = db.parse(new File("src/forum11465653/input.xml"));
        Node getNumberResponseElt = d.getElementsByTagNameNS("http://example.com/", "getNumberResponse").item(0);

        JAXBContext jc = JAXBContext.newInstance(Response.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBElement<Response> je = unmarshaller.unmarshal(new DOMSource(getNumberResponseElt), Response.class);
        System.out.println(je.getName());
        System.out.println(je.getValue());
    }

}

输出

{http://example.com/}getNumberResponse
forum11465653.Response@19632847
于 2012-07-13T08:43:43.017 回答