2012-04-08 17 views
7

Tengo una situación en la que llamo a un servicio web y me devuelve algo de HTML en un sobre XML. como:Android org.xmlpull.v1.XmlPullParserException al analizar XML

<xml version="1.0" cache="false"> 
<head/> 
<body> 
<table> 
<tr> 
    <td> 
     <a href="link-to-prev-post"> 
      <text color="red"><< Prev</text> 
     </a> 
    </td> 
    <td> 
     <a href="link-to-next-post"> 
      <text color="red">| Next >></text> 
     </a> 
    </td> 
</tr> 
</table> 
</body> 
</xml> 

tengo que recuperar los enlace-a-ant-post & enlace-a-lado-post enlaces .. para que pueda obtener más datos a través de estos enlaces.

Estoy usando XmlPullParser para analizar el XML/HTML proporcionado anteriormente. Para obtener los enlaces para próximos artículos/prev, que estoy haciendo de la siguiente manera:

if (xmlNodeName.equalsIgnoreCase("a")) { 
       link = parser.getAttributeValue(null, "href"); 

      } else if (xmlNodeName.equalsIgnoreCase("text")) { 
       color = parser.getAttributeValue(null, "color"); 

       if (color.equalsIgnoreCase("red") && parser.getEventType() == XmlPullParser.START_TAG) { 
         // check for next/prev blog entries links 
         // but this parser.nextText() throws XmlPullParserException 
         // i think because the nextText() returns << Prev which the parser considers to be wrong 
         String innerText = parser.nextText(); 
         if (innerText.contains("<< Prev")) { 
          blog.setPrevBlogItemsUrl(link);        
         } else if (innerText.contains("Next >>")) { 
          blog.setNextBlogItemsUrl(link); 
         } 
        } 

        link = null; 
       } 
      } 

Se lanza XmlPullParserException en la ejecución de parser.nextText() ... y el valor del elemento de texto en este el tiempo es < < Anterior .. creo que no entiende este valor con etiqueta de inicio debido a la presencia de < < en el texto ..

detalle LogCat es:

04-08 18:32:09.827: W/System.err(688): org.xmlpull.v1.XmlPullParserException: precondition: START_TAG (position:END_TAG </text>@9:2535 in [email protected]) 
04-08 18:32:09.827: W/System.err(688): at org.kxml2.io.KXmlParser.exception(KXmlParser.java:245) 
04-08 18:32:09.827: W/System.err(688): at org.kxml2.io.KXmlParser.nextText(KXmlParser.java:1382) 
04-08 18:32:09.827: W/System.err(688): at utilities.XMLParserHelper.parseBlogEntries(XMLParserHelper.java:139) 
04-08 18:32:09.827: W/System.err(688): at serviceclients.PlayerSummaryAsyncTask.doInBackground(PlayerSummaryAsyncTask.java:68) 
04-08 18:32:09.827: W/System.err(688): at serviceclients.PlayerSummaryAsyncTask.doInBackground(PlayerSummaryAsyncTask.java:1) 
04-08 18:32:09.836: W/System.err(688): at android.os.AsyncTask$2.call(AsyncTask.java:185) 
04-08 18:32:09.836: W/System.err(688): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
04-08 18:32:09.836: W/System.err(688): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
04-08 18:32:09.836: W/System.err(688): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) 
04-08 18:32:09.836: W/System.err(688): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) 
04-08 18:32:09.836: W/System.err(688): at java.lang.Thread.run(Thread.java:1096) 

espero haber aclarado mi problema.

Solución

Isnpired por Martin's enfoque de convertir los datos recibidos primero en cadena, he conseguido mi problema en una especie de enfoque mixto.

  1. Convertir valor de la recibida InputStream 's de la cadena y reemplazado los caracteres erróneos con * (o lo que usted desee): la siguiente manera

    InputStreamReader isr = new InputStreamReader(serviceReturnedStream); 
    
    BufferedReader br = new BufferedReader(isr); 
    StringBuilder xmlAsString = new StringBuilder(512); 
    String line; 
    try { 
        while ((line = br.readLine()) != null) { 
         xmlAsString.append(line.replace("<<", "*").replace(">>", "*")); 
        } 
    } catch (IOException e) { 
        e.printStackTrace(); 
    } 
    
  2. Ahora tengo una cadena que contiene correcta datos XML (para mi caso), por lo que sólo utilizan el XmlPullParser normal a analizarlo en lugar de analizar manualmente a mí mismo:

    XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 
    
    factory.setNamespaceAware(false); 
    
    XmlPullParser parser = factory.newPullParser(); 
    parser.setInput(new StringReader(xmlAsString.toString())); 
    

Espero que esto ayude a alguien!

Respuesta

6

Sí, la excepción es, probablemente, porque eso es arrojado XML no válido según la sección 2.4 Character Data and Markup en la especificación XML 1.0:

[...] la escuadra izquierda (<) NO DEBE aparecer en [su ] forma literal, [...]

Si coloca ese XML en Eclipse, Eclipse se quejará de que el XML no es válido. Si puede reparar el servicio web, debe corregir el XML generado, ya sea utilizando referencias de entidad como &lt; o usando CDATA.

Si no tiene poder sobre el servicio web, creo que lo más fácil será analizarlo manualmente con algún código personalizado, tal vez usando regular expressions, dependiendo de qué tan relajados sean los requisitos de generalidad que tenga.

Ejemplo Código

Así es como se podría analizar el archivo XML anterior. Tenga en cuenta que es probable que desee para mejorar el código para que sea más general, pero usted debe tener algo para empezar con al menos:

// Read the XML into a StringBuilder so we can get get a Matcher for the 
    // whole XML 
    InputStream xmlResponseInputStream = // Get InputStream to XML somehow 
    InputStreamReader isr = new InputStreamReader(xmlResponseInputStream); 
    BufferedReader br = new BufferedReader(isr); 
    StringBuilder xmlAsString = new StringBuilder(512); 
    String line; 
    try { 
     while ((line = br.readLine()) != null) { 
      xmlAsString.append(line); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    // Look for links using a regex. Assume the first link is "Prev" and the 
    // next link is "Next" 
    Pattern hrefRegex = Pattern.compile("<a href=\"([^\"]*)\">"); 
    Matcher m = hrefRegex.matcher(xmlAsString); 
    String linkToPrevPost = null; 
    String linkToNextPost = null; 
    while (m.find()) { 
     String hrefValue = m.group(1); 
     if (linkToPrevPost == null) { 
      linkToPrevPost = hrefValue; 
     } else { 
      linkToNextPost = hrefValue; 
     } 
    } 

    Log.i("Example", "'Prev' link = " + linkToPrevPost + 
      " 'Next' link = " + linkToNextPost); 

Con el archivo XML, la salida a Logcat habrá

I/Example (12399): 'Prev' link = link-to-prev-post 'Next' link = link-to-next-post 
+0

gracias por la explicación ... en realidad no tengo control sobre el servicio web, así que no puedo cambiar lo que devuelve ... usar expresiones regulares suena bien, pero el problema surge cuando intento leer los datos usando _parser.nextText() _ .. así que creo que Regex no se puede usar tan bien porque primero tendré que obtener el texto antes de analizarlo a través de expresiones regulares ... pero si crees que se puede hacer, ¿puedes por favor darme algunos ejemplo amplio? eso seria genial. – Aamir

+0

¡Me alegra ayudar! En realidad, me refería a analizar el XML completo manualmente, es decir, no utilizar el analizador XML en absoluto (ya que no es XML válido que está analizando). –

+0

ok i umnderstand now .. pero ¿cómo propondrías tal análisis manual? Estoy buscando un ejemplo ... ya que estoy muy atascado – Aamir

Cuestiones relacionadas