2011-01-10 22 views
9

Estoy usando stax por primera vez para analizar una cadena XML. He encontrado algunos ejemplos pero no puedo hacer que mi código funcione. Esta es la última versión de mi código:Leer cadena XML usando 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); 
     } 
    } 
} 

He puesto relojes de "evento" y "reader.getElementText()". Cuando el código se detuvo en

String element = reader.getLocalName(); 

se muestra el valor "reader.getElementText()", pero en cuanto se aleja de esa línea no se puede evaluar. Cuando se detiene el código:

status = reader.getElementText(); 

el reloj "element" muestra el valor correcto. Finalmente, cuando me paso el código de una línea más, esta captura de excepción:

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

He intentado usar status = reader.getText(); lugar, pero luego me sale esta excepción:

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

Puede alguien señalar lo Estoy haciendo mal?

EDIT:

Adición de código JUnit utilizado para la prueba:

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

¿Qué datos XML se parecen? ¿Estás seguro de que está bien formado? (Quizás nos muestre una pequeña cantidad) –

+0

El XML es una respuesta de Cadena de otra clase/método que mi código llamará. Estoy escribiendo un JUnit para probar el analizador. Agregué el código JUnit a la pregunta, incluido el método que genera el XML para la prueba. – sdoca

+1

mi enfoque personal sería encontrar un tutorial stAX y asegurarme de que funciona para mí, luego extenderlo para cubrir sus necesidades. Recuerdo que solo atrapaste START_ELEMENT. Agregaría una cláusula '} else {' que registra los otros eventos. Eso te dirá qué tan lejos has llegado a través de los datos. –

Respuesta

7

he encontrado una solución que utiliza XMLEventReader en lugar de 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; 
} 

todavía estaría interesado en ver una solución usando XMLStreamReader.

4

Asegúrese de leer javadocs para Stax: dado que se trata de un modo de transmisión en tiempo real, solo está disponible la información contenida en el evento actual. Sin embargo, hay algunas excepciones; getElementText(), por ejemplo, debe comenzar en START_ELEMENT, pero luego intentará combinar todos los tokens de texto del elemento actual; y cuando regrese, apuntará a la coincidencia de END_ELEMENT.

Por el contrario, getText() en START_ELEMENT no devolverá nada útil (ya que START_ELEMENT hace referencia a la etiqueta, no a los tokens/nodes de texto hijo 'dentro' del par de elementos de inicio/final). Si desea usarlo en su lugar, debe mover el cursor explícitamente en la ruta al llamar a streamReader.next(); mientras que getElementText() lo hace por ti.

¿Qué está causando el error? Después de haber consumido todos los pares de elementos de inicio/final, el próximo token será END_ELEMENT (haciendo coincidir lo que sea la etiqueta principal). Por lo tanto, debe verificar el caso en el que obtiene END_ELEMENT en lugar de START_ELEMENT.

+0

+1 Esta respuesta parece ser correcta. –

2

que se enfrentaron a un problema similar ya que llegaba "IllegalStateException: No es un evento textual" mensaje Cuando miré a través de su código me di cuenta de que si había una condición:

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

(Tenga en cuenta: ¡StaXMan sí lo señaló en su respuesta!)

Esto sucede porque para obtener texto, la instancia de XMLStreamReader debe haber encontrado el evento 'XMLStreamConstants.CHARACTERS'.

Quizás haya una mejor manera de hacer esto ...pero esto es una solución rápida y sucia ( He líneas de código que pueden ser de interés solamente se muestra) ahora para que esto suceda modificar ligeramente su código:

// 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; 

}  

} 

Espero que ayude!

0

Aquí se muestra un ejemplo con 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); 
} 
Cuestiones relacionadas