2011-01-10 2 views
9

Я использую stax для анализа XML-строки в первый раз. Я нашел несколько примеров, но не могу заставить мой код работать. Это последняя версия моего кода:Чтение XML-строки с использованием StAX

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) 

Может кто-нибудь указать на то, что Я делаю неправильно?

EDIT:

Добавление кода 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(); 
    } 
} 
+0

Что искать ваши данные XML как? Вы уверены, что он хорошо сформирован? (Возможно, покажите нам небольшую сумму) –

+0

XML - это ответ строки из другого класса/метода, который будет вызывать мой код. Я пишу JUnit для проверки парсера. Я добавил код JUnit к вопросу, включая метод, который генерирует XML для теста. – sdoca

+1

моим личным подходом было бы найти учебник stAX и убедиться, что он работает для меня, а затем расширьте его, чтобы покрыть ваши требования. Я отмечаю, что вы только ловушки START_ELEMENT - я бы добавил '} else {' предложение, которое регистрирует другие события. Это расскажет вам, как далеко вы прошли данные. –

ответ

7

Я нашел решение, которое использует 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.

4

Убедитесь, что вы прочитали javadocs для Stax: поскольку он полностью потоковый режим синтаксического анализа, доступна только информация, содержащаяся в текущем событии. Однако есть некоторые исключения; getElementText(), например, должен начинаться с START_ELEMENT, но затем попытается объединить все текстовые токены изнутри текущего элемента; и при возврате он укажет на соответствие END_ELEMENT.

И наоборот, getText() в START_ELEMENT не вернет ничего полезного (поскольку START_ELEMENT ссылается на тег, а не на дочерние текстовые маркеры/узлы внутри пары «начало/конец элемента»). Если вы хотите использовать его вместо этого, вы должны явно перемещать курсор в потоке, вызывая streamReader.next(); тогда как getElementText() делает это для вас.

И что вызывает ошибку? После того, как вы уничтожили все пары start/end-element, следующий токен будет END_ELEMENT (совпадающий с тем, что было родительским тегом). Поэтому вы должны проверить, в каком случае вы получите END_ELEMENT, а не еще один START_ELEMENT.

+0

+1 Этот ответ кажется правильным. –

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; 

}  

} 

Надежда, что помогает!

0

Вот пример с 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); 
} 
Смежные вопросы