5

我的wsdl2java目标是cxf-codegen-plugin从 WSDL 生成 Java。然后,在我的测试中,我使用 JAXB.unmarshal() 从原始 Web 服务 XML 结果填充类。

一个典型的例子是GetAllResponseType response = unmarshal("get-all.xml", GetAllResponseType.class),使用以下方法:

<T> T unmarshal(String filename, Class<T> clazz) throws Exception {
    InputStream body = getClass().getResourceAsStream(filename);
    return javax.xml.bind.JAXB.unmarshal(body, clazz);
}

问题是这样的:原始 XML 响应总是有封闭的 Envelope 和 Body 标记,它们不是由 wsdl2java 作为类生成的:

<n4:Envelope xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:n="http://www.informatica.com/wsdl/"
         xmlns:n4="http://schemas.xmlsoap.org/soap/envelope/" xmlns:n5="http://schemas.xmlsoap.org/wsdl/"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <n4:Body>
    <n:getAllResponse xmlns:n="http://www.informatica.com/wsdl/">
        <n:getAllResponseElement>
           ...
        </n:getAllResponseElement>
    </n:getAllResponse>
  </n4:Body>
</n4:Envelope>

所以,为了使用 JAXB.unmarshal() 我必须

  1. 在 get-all.xml 中手动剥离周围的 Envelope/Body 标签
  2. 或提取 getAllResponse 节点并将其重新转换为 InputStream
  3. 或创建 Envelope 和 Body 类

目前我做2,但它有很多代码:

<T> T unmarshal(String filename, Class<T> clazz) throws Exception {
    InputStream is = getClass().getResourceAsStream(filename);
    InputStream body = nodeContent(is, "n4:Body");
    return javax.xml.bind.JAXB.unmarshal(body, clazz);
}

InputStream nodeContent(InputStream is, String name) throws Exception {
    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
    Document doc = docBuilder.parse(is);
    Node node = firstNonTextNode(doc.getElementsByTagName(name).item(0).getChildNodes());
    return nodeToStream(node);
}

Node firstNonTextNode(NodeList nl) {
    for (int i = 0; i < nl.getLength(); i++) {
        if (!(nl.item(i) instanceof Text)) {
            return nl.item(i);
        }
    }
    throw new RuntimeException("Couldn't find nontext node");
}

InputStream nodeToStream(Node node) throws Exception {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    Source xmlSource = new DOMSource(node);
    Result outputTarget = new StreamResult(outputStream);
    TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
    return new ByteArrayInputStream(outputStream.toByteArray());
}

我的问题是:

  • 有没有更简单的方法来提取2?我很想只做一个正则表达式。我尝试了 XPath,但不知何故我无法让它工作。代码示例会很有帮助。
  • 我可以让 wsdl2java 创建 Body / Envelope 类(3),还是自己创建它们很容易?
4

3 回答 3

4

使用DOMSource传递一个节点作为输入。以下方法将 aorg.w3c.dom.Node作为输入并返回未编组的类。

private <T> T unmarshal(Node node, Class<T> clazz) throws JAXBException {
        XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
        Source xmlSource = new DOMSource(node);
        Unmarshaller unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
        return unmarshaller.unmarshal(xmlSource, clazz).getValue();
}
于 2017-04-20T20:30:55.280 回答
2

节点内的n4:Body节点可以通过使用XMLStreamReader“原始”JAXB来解组Unmarshaller

<T> T unmarshal(String filename, Class<T> clazz) throws Exception {
    XMLInputFactory xif = XMLInputFactory.newFactory();
    XMLStreamReader xsr = xif.createXMLStreamReader(getClass().getResourceAsStream(filename));
    xsr.nextTag();
    while (!xsr.getLocalName().equals("Body")) {
        xsr.nextTag();
    }
    xsr.nextTag();
    Unmarshaller unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
    return unmarshaller.unmarshal(xsr, clazz).getValue();
}

感谢 Blaise Doughan 帮助回答这个问题。

于 2013-06-11T12:07:23.787 回答
1

您可以使用 StAXXmlStreamReader解析 XML,然后将其推进到要解组的元素,并让您的 JAXB 实现解组XmlStreamReader

了解更多信息

于 2013-06-10T09:20:24.653 回答