我从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>
由于基本结构将保持不变,我最初的想法是:
有更好的方法吗?
更新
尝试@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();
}
}
-
答案 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();