使用StAX读取XML字符串

我第一次使用stax来解析XML String。 我找到了一些例子,但无法让我的代码工作。 这是我的代码的最新版本:

public class AddressResponseParser { private static final String STATUS = "status"; private static final String ADDRESS_ID = "address_id"; private static final String CIVIC_ADDRESS = "civic_address"; String status = null; String addressId = null; String civicAddress = null; public static AddressResponse parseAddressResponse(String response) { try { byte[] byteArray = response.getBytes("UTF-8"); ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArray); XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLStreamReader reader = inputFactory.createXMLStreamReader(inputStream); while (reader.hasNext()) { int event = reader.next(); if (event == XMLStreamConstants.START_ELEMENT) { String element = reader.getLocalName(); if (element.equals(STATUS)) { status = reader.getElementText(); continue; } if (element.equals(ADDRESS_ID)) { addressId = reader.getText(); continue; } if (element.equals(CIVIC_ADDRESS)) { civicAddress = reader.getText(); continue; } } } } catch (Exception e) { log.error("Couldn't parse AddressResponse", e); } } } 

我把手表放在“event”和“reader.getElementText()”上。 代码停止时

 String element = reader.getLocalName(); 

显示“reader.getElementText()”值,但一旦离开该行,就无法对其进行评估。 当代码停止时:

 status = reader.getElementText(); 

“元素”手表显示正确的值。 最后,当我再添加一行代码时,我会抓住这个exception:

 (com.ctc.wstx.exc.WstxParsingException) com.ctc.wstx.exc.WstxParsingException: Current state not START_ELEMENT at [row,col {unknown-source}]: [1,29] 

我尝试过使用status = reader.getText(); 相反,但后来我得到这个例外:

 (java.lang.IllegalStateException) java.lang.IllegalStateException: Not a textual event (END_ELEMENT) 

谁能指出我做错了什么?

编辑:

添加用于测试的JUnit代码:

 public class AddressResponseParserTest { private String status = "OK"; private String address_id = "123456"; private String civic_address = "727"; @Test public void testAddressResponseParser() throws UnsupportedEncodingException, XMLStreamException { AddressResponse parsedResponse = AddressResponseParser.parseAddressResponse(this.responseXML()); assertEquals(this.status, parsedResponse.getStatus()); assertEquals(this.address_id, parsedResponse.getAddress() .getAddressId()); assertEquals(this.civic_address, parsedResponse.getAddress() .getCivicAddress()); } private String responseXML() { StringBuffer buffer = new StringBuffer(); buffer.append(""); buffer.append("OK"); buffer.append("
"); buffer.append("
123456
"); buffer.append("727"); buffer.append("
"); buffer.append(""); return buffer.toString(); } }

我找到了一个使用XMLEventReader而不是XMLStreamReader的解决方案:

 public MyObject parseXML(String xml) throws XMLStreamException, UnsupportedEncodingException { byte[] byteArray = xml.getBytes("UTF-8"); ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArray); XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLEventReader reader = inputFactory.createXMLEventReader(inputStream); MyObject object = new MyObject(); while (reader.hasNext()) { XMLEvent event = (XMLEvent) reader.next(); if (event.isStartElement()) { StartElement element = event.asStartElement(); if (element.getName().getLocalPart().equals("ElementOne")) { event = (XMLEvent) reader.next(); if (event.isCharacters()) { String elementOne = event.asCharacters().getData(); object.setElementOne(elementOne); } continue; } if (element.getName().getLocalPart().equals("ElementTwo")) { event = (XMLEvent) reader.next(); if (event.isCharacters()) { String elementTwo = event.asCharacters().getData(); object.setElementTwo(elementTwo); } continue; } } } return object; } 

我仍然有兴趣看到使用XMLStreamReader的解决方案。

确保您读取了Stax的javadoc:由于它是完全流式解析模式,因此只有当前事件包含的信息可用。 但是有一些例外; 例如,getElementText()必须从START_ELEMENT开始,但是会尝试从当前元素内部组合所有文本标记; 返回时,它将指向匹配END_ELEMENT。

相反,START_ELEMENT上的getText()不会返回任何有用的内容(因为START_ELEMENT引用标记,而不是’start / end元素对内的子文本标记/节点’)。 如果你想改用它,你必须通过调用streamReader.next()显式地在游标中移动游标; 而getElementText()为你做。

那么是什么导致错误? 在使用了所有开始/结束元素对之后,下一个标记将是END_ELEMENT(匹配父标记的任何内容)。 因此,您必须检查END_ELEMENT的情况,而不是另一个START_ELEMENT。

我遇到了类似的问题,因为我收到“IllegalStateException:Not a textual event”消息当我查看你的代码时,我发现如果你有条件:

 if (event == XMLStreamConstants.START_ELEMENT){ .... addressId = reader.getText(); // it throws exception here .... } 

(请注意:StaXMan在他的回答中指出了这一点!)

这是因为要获取文本,XMLStreamReader实例必须遇到’XMLStreamConstants.CHARACTERS’事件!

有一种更好的方法可以做到这一点……但这是一个快速而又脏的修复( 我只展示了可能感兴趣的代码行 )现在为了实现这一点,请稍微修改一下代码:

 // this will tell the XMLStreamReader that it is appropriate to read the text boolean pickupText = false while(reader.hasNext()){ if (event == XMLStreamConstants.START_ELEMENT){ if( (reader.getLocalName().equals(STATUS) ) || ( (reader.getLocalName().equals(STATUS) ) || ((reader.getLocalName().equals(STATUS) )) // indicate the reader that it has to pick text soon! pickupText = true; } }else if (event == XMLStreamConstants.CHARACTERS){ String textFromXML = reader.getText(); // process textFromXML ... //... //set pickUpText false pickupText = false; } } 

希望有所帮助!

以下是XMLStreamReader的示例:

  XMLInputFactory inputFactory = XMLInputFactory.newInstance(); try { XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(file); String elementValue = ""; while (xmlReader.hasNext()) { int xmlEventType = xmlReader.next(); switch (xmlEventType) { // Check for Start Elements case XMLStreamConstants.START_ELEMENT: //Get current Element Name String elementName = xmlReader.getLocalName(); if(elementName.equals("td")) { //Get Elements Value elementValue = xmlReader.getElementText(); } //Add the new Start Element to the Map elements.put(elementName, elementValue); break; default: break; } } //Close Session xmlReader.close(); } catch (Exception e) { log.error(e.getMessage(), e); }