Search code examples
javaandroidxmlxml-parsing

Android Java XMLParser issue


Im outsourcing to openweathermap API to retrieve results.

I then loop through the results and then it crashes when it hits the "timezone" tag.

Here is the code:

URL url = new URL("https://api.openweathermap.org/data/2.5/weather?q=toronto,ca&APPID=***&mode=xml&units=metric");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query.
conn.connect();
InputStream is = conn.getInputStream();

XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);

while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    if(parser.getEventType() == XmlPullParser.START_TAG) {
        String loopTag = parser.getName();
        Log.i("weather", loopTag);
        if (loopTag.equals("temperature")) {
            min = parser.getAttributeValue(null, "min");
            max = parser.getAttributeValue(null, "max");
            curr = parser.getAttributeValue(null, "value");
        } else if (loopTag.equals("weather")) {
            icon = parser.getAttributeValue(null, "icon");
        }
    }
    parser.nextTag();
}

The xml trying to retrieve data:

<current>
    <city id="6167865" name="Toronto">
       <coord lon="-79.4163" lat="43.7001"/>
       <country>CA</country>
       <timezone>-14400</timezone>
       <sun rise="2023-07-12T09:46:54" set="2023-07-13T00:59:13"/>
    </city>
    <temperature value="20.57" min="19.15" max="21.94" unit="celsius"/>
    <feels_like value="20.28" unit="celsius"/>
    <humidity value="61" unit="%"/>
    <pressure value="1013" unit="hPa"/>
    <wind>
        <speed value="1.79" unit="m/s" name="Light breeze"/>
        <gusts value="4.47"/>
        <direction value="314" code="NW" name="Northwest"/>
    </wind>
    <clouds value="98" name="overcast clouds"/>
    <visibility value="10000"/>
    <precipitation mode="no"/>
    <weather number="804" value="overcast clouds" icon="04d"/>
    <lastupdate value="2023-07-12T15:07:14"/>
</current>

I've been able to log the names as can be seen in the while loop: I log out:

  • current
  • city
  • coord
  • country

Then it errors out with:

Caused by: java.lang.RuntimeException: org.xmlpull.v1.XmlPullParserException: unexpected type (position:TEXT CA@2:99 in java.io.InputStreamReader@59ac190)

I've read somewhere that if the xml is in UTF-8 BOM it can cause this issue. But I don't think it is the case here.

What could be the issue here?


Solution

  • I tested your xml and your code and I got different exception (but maybe the xml is differently formatted):

    org.xmlpull.v1.XmlPullParserException: unexpected type (position:TEXT CA@3:19 in java.io.InputStreamReader@8152fb6)

    which is :

    <country>CA</country>
    

    it originates from the parser.nextTag(); call which in documentation has:

    Call next() and return event if it is START_TAG or END_TAG otherwise throw an exception. It will skip whitespace TEXT before actual tag if any.

    in the case of <country> tag you consume tag, but then call nextTag() which expect either START or END or whitespace TEXT but finds TEXT with actuall text: CA. Which is what the exception message is saying.

    One solution is to skip the TEXT in country and timezone tags:

    else if (loopTag.equals("country")) {
        parser.next();
     } else if (loopTag.equals("timezone")) {
         parser.next();
     }
    

    the other is to use parser.next instead of parser.nextTag.