2012-04-08 15 views
7

Ho una situazione in cui io chiamo un servizio Web e mi restituisce del codice HTML in una busta XML. come:Android org.xmlpull.v1.XmlPullParserException durante l'analisi 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> 

devo recuperare i link-to-prev-post & link-to-next-post link .. così posso ottenere più dati attraverso questi collegamenti.

Sto usando XmlPullParser per analizzare l'XML/HTML fornito sopra. Per ottenere i link per gli articoli/prev next, sto facendo come segue:

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

Getta XmlPullParserException in esecuzione di parser.nextText() ... e il valore dell'elemento di testo a questo il tempo è < < Prec .. penso che fraintende questo valore con tag di apertura a causa della presenza di < < nel testo ..

dettaglio LogCat è:

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) 

Spero di aver chiarito il mio problema.

Soluzione

Isnpired da Martin's approccio di convertire i dati ricevuti prima a stringa, sono riuscito il mio problema in una sorta di approccio misto.

  1. Convertire il valore ricevuto InputStream s' a stringa e sostituito i caratteri errati con * (o qualsiasi altra cosa che si desidera): come segue

    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. Ora ho una stringa che contiene corretta dati XML (per il mio caso), quindi basta utilizzare il XmlPullParser normale per analizzare invece di parsing manualmente io stesso:

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

Spero che questo aiuti qualcuno!

risposta

6

Sì, l'eccezione viene generata probabilmente perché questo è XML non valido ai sensi dell'articolo 2.4 Character Data and Markup nella specifica XML 1.0:

[...] la parentesi angolare sinistra (<) non deve apparire nel [suo ] forma letterale, [...]

Se si inserisce quell'XML in Eclipse, Eclipse si lamenterà del fatto che XML non è valido. Se è possibile risolvere il servizio Web, è necessario correggere l'XML generato, utilizzando riferimenti di entità come &lt; o utilizzando CDATA.

Se non si ha il potere sul servizio web, penso che il più semplice sarà analizzarlo manualmente con un codice personalizzato, magari usando regular expressions, a seconda di quanto siano rilassati i requisiti di generalità.

Esempio Codice

Ecco come si potrebbe analizzare il file XML di cui sopra. Si noti che, probabilmente, si vuole migliorare questo codice per renderlo più generale, ma si dovrebbe avere qualcosa da cui partire con almeno:

// 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 il vostro file XML, l'output di logcat sarà

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

grazie per la spiegazione ... in realtà non ho alcun controllo sul servizio web, quindi non posso cambiare cosa è ritornato ... usare le espressioni regolari sembra buono ma il problema sorge quando provo a leggere i dati usando _parser.nextText() _ .. Quindi penso che la regex non possa essere usata come bene bcoz dovrò prima ottenere il testo prima di analizzarlo attraverso la regex .. ma se pensi che possa essere fatto allora puoi darmi qualche cosa ampio esempio ?? sarebbe grandioso. – Aamir

+0

Sono felice di aiutare! In realtà mi stavo riferendo all'analisi dell'intero XML manualmente, cioè non utilizzando affatto il parser XML (poiché non si tratta di XML valido che si sta analizzando). –

+0

ok ho capito adesso .. ma come proporresti un simile parsing manuale? sto cercando un esempio ... sono bloccato male – Aamir

Problemi correlati