10

我第一次使用 stax 来解析 XML 字符串。我找到了一些示例,但无法使我的代码正常工作。这是我的代码的最新版本:

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);
        }
    }
}

我已经在“事件”和“reader.getElementText()”上放置了手表。当代码停止时

String element = reader.getLocalName();

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

status = reader.getElementText();

“元素”手表显示正确的值。最后,当我将代码再执行一行时,我发现了这个异常:

(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("<response>");
        buffer.append("<status>OK</status>");
        buffer.append("<address>");
        buffer.append("<address_id>123456</address_id>");
        buffer.append("<civic_address>727</civic_address>");
        buffer.append("</address>");
        buffer.append("</response>");

        return buffer.toString();
    }
}
4

4 回答 4

9

我找到了一个使用 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 的解决方案。

于 2011-01-11T16:49:22.933 回答
5

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

相反, START_ELEMENT 上的 getText() 不会返回任何有用的东西(因为 START_ELEMENT 指的是标签,而不是子文本标记/节点“内部”开始/结束元素对)。如果你想改用它,你必须通过调用 streamReader.next() 来显式移动光标到流中;而 getElementText() 为您完成。

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

于 2011-05-31T22:15:01.643 回答
2

当我收到“IllegalStateException:不是文本事件”消息时,我遇到了类似的问题当我查看您的代码时,我发现如果您有一个条件:

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;

 }    

}

希望有帮助!

于 2011-08-11T21:11:23.403 回答
0

以下是 XMLStreamReader 的示例:

   XMLInputFactory inputFactory = XMLInputFactory.newInstance();
   Map<String, String> elements = new HashMap<>();

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);
}
于 2014-02-13T13:46:33.903 回答