如何使用内联架构处理XML字符串到java对象?

时间:2014-08-12 17:12:04

标签: java jaxb xsd

我从Java代理调用WCF .Net服务。结果是带有内联架构的xml字符串(在流中)。我想使用JAXB将xml中的值解组为Java类。 xml字符串如下所示:

<NewDataSet>
  <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Table">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="CustomerID" type="xs:int" minOccurs="0" />
                <xs:element name="CustomerNme" type="xs:string" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>
  <Table>
    <CustomerID>1111</CustomerID>
    <CustomerNme>Customer One</CustomerNme>
  </Table>
  <Table>
    <CustomerID>2222</CustomerID>
    <CustomerNme>Customer Two</CustomerNme>
  </Table>
</NewDataSet>

由于基本结构将保持不变,我最初的想法是:

  1. 使用模式使用xjc手动创建JAXB Java类。
  2. 在处理过程中,使用嵌入式模式解析xml字符串,并丢弃模式和根节点NewDataSet。
  3. 使用JAXB将字符串解组为java对象。
  4. 有更好的方法吗?

    更新

    尝试@Doughans方法。关闭但没有雪茄。复杂的是xml来了gzip。所以,下面的代码是我所需要的。我已将Customer类成员设置为大写以匹配确切的xml元素,但对于每个unmarshal操作实例,我获得的所有内容都为null。

    //everything good to here...
    JAXBElement<byte[]> byteRet = searchCustResponse.getSearchCustomersResult();
    byte[] gzBytes = byteRet.getValue(); //these are gzipped bytes
    
    //decompress...
    ByteArrayInputStream bais = new ByteArrayInputStream(gzBytes);
    GZIPInputStream gzipis = new GZIPInputStream(bais);
    //InputStreamReader isr = new InputStreamReader(gzipis, "UTF-8");
    
    //convert xml to string...
    StringWriter writer = new StringWriter();
    IOUtils.copy(gzipis, writer, "UTF-8");
    String xmlString = writer.toString();
    
    //read the string...
    //StreamSource xml = new StreamSource(xmlString);
    Reader reader = new StringReader(xmlString);
    
    XMLInputFactory xif = XMLInputFactory.newFactory();
    XMLStreamReader xsr = xif.createXMLStreamReader(reader);
    
    List<WPTSCustomer> wptsCustomers = new ArrayList<WPTSCustomer>();
    
    try {
        while (xsr.hasNext()) {
            int next = xsr.next();
            //xsr.nextTag();
            if (next == XMLStreamReader.START_ELEMENT) {
                if (xsr.getLocalName().equals("Table")) {
                    JAXBContext jc = JAXBContext.newInstance(WPTSCustomer.class);
                    Unmarshaller unmarshaller = jc.createUnmarshaller();
                    JAXBElement<WPTSCustomer> jb = unmarshaller.unmarshal(xsr, WPTSCustomer.class);
                    WPTSCustomer customer = jb.getValue();
                    System.out.println(customer.getCustomerID()); //prints null
                    System.out.println(customer.getCustomerNme()); //prints null
                    wptsCustomers.add(customer);
                }
            }
        }
    } finally {
    

    使用StreamSource对我不起作用。最后,我只是走了xml字符串,这就是它解决了没有填充对象的unmarshal的问题。

    UPDATE2

    现在放弃JAXB。以下代码很好地工作,我只是将值抛入我的POJO。我尝试从服务返回的完整xml字符串中创建JDev中的XSD,然后尝试从XSD创建JAXB类。除了来自内联架构的名称冲突之外,这几乎起作用了。可能有办法解决这个问题。

    int eventType = xsr.getEventType();
    while (xsr.hasNext()) {
        eventType = xsr.next();
        if (xsr.isStartElement() && xsr.getLocalName().equals("Table")) {
            xsr.nextTag();
            while (xsr.hasNext()) {
                if (xsr.isStartElement()) {
                    if (xsr.getLocalName().equals("CustomerID")) {
                        System.out.println("id: " + xsr.getElementText());
                    }
                    if (xsr.getLocalName().equals("CustomerNme")) {
                        System.out.println("name: " + xsr.getElementText());
                    }
                }
                xsr.next();
            }
        }
    

    -

2 个答案:

答案 0 :(得分:2)

我将使用StAX解析整个XML文档,然后将XMLStreamReader向下导航到Table元素并使用JAXB解组。

了解更多信息

我在博客上写了更多关于此用例的内容:

答案 1 :(得分:1)

对于可能再次遇到此问题的人,如果您尝试从xml字符串中读取数据,它可能无效,但如果您可以在InputStream中获取数据,则可以将其传递给XMLStreamReader它工作正常。 @Blaise的精彩博客。

我使用xjc选择手动创建Javaobject的模式,然后使用 XMLStreamReader 来解析jax-rs响应并获取输入流。如果成功,将尝试删除手动步骤并更新帖子。

XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource(httpResponse.getEntity().getContent());
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
xsr.nextTag();
while (!xsr.getLocalName().equals("GetAccountInfoResults")) {
    xsr.nextTag();
}
JAXBContext jc = JAXBContext.newInstance(GetAccountInfoResults.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<GetAccountInfoResults> jb = unmarshaller.unmarshal(xsr, GetAccountInfoResults.class);
xsr.close();

GetAccountInfoResults result = jb.getValue();