0

I am using World Weather Online API to get the weathers of specific location. My problem is while I am trying to deserialize XML output coming from API Response stream, I am getting error with: There is a problem with XML document (1,1).

    Uri apiURL = new Uri(@"http://api.worldweatheronline.com/free/v1/weather.ashx?q=Dhaka&format=xml&num_of_days=1&date=today&key=jzb88bpzb5yvaegukmq97mee");

    Stream result = RequestHandler.Process(apiURL.ToString());
    XmlSerializer des = new XmlSerializer(typeof(LocalWeather));
    StreamReader tr = new StreamReader(result);
    Object obj = des.Deserialize(tr);
    LocalWeather data = (LocalWeather)obj;

Sample XML file from Web API:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <request>
        <type>City</type>
        <query>Dhaka, Bangladesh</query>
    </request>
    <current_condition>
        <observation_time>01:57 PM</observation_time>
        <temp_C>33</temp_C>
        <temp_F>91</temp_F>
        <weatherCode>113</weatherCode>
        <weatherIconUrl>
            <![CDATA[http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0008_clear_sky_night.png]]>
        </weatherIconUrl>
        <weatherDesc>
            <![CDATA[Clear ]]>
        </weatherDesc>
        <windspeedMiles>2</windspeedMiles>
        <windspeedKmph>4</windspeedKmph>
        <winddirDegree>77</winddirDegree>
        <winddir16Point>ENE</winddir16Point>
        <precipMM>0.0</precipMM>
        <humidity>76</humidity>
        <visibility>10</visibility>
        <pressure>1006</pressure>
        <cloudcover>2</cloudcover>
    </current_condition>
    <weather>
        <date>2013-10-11</date>
        <tempMaxC>36</tempMaxC>
        <tempMaxF>97</tempMaxF>
        <tempMinC>25</tempMinC>
        <tempMinF>77</tempMinF>
        <windspeedMiles>5</windspeedMiles>
        <windspeedKmph>8</windspeedKmph>
        <winddirection>ENE</winddirection>
        <winddir16Point>ENE</winddir16Point>
        <winddirDegree>65</winddirDegree>
        <weatherCode>113</weatherCode>
        <weatherIconUrl>
            <![CDATA[http://cdn.worldweatheronline.net/images/wsymbols01_png_64/wsymbol_0001_sunny.png]]>
        </weatherIconUrl>
        <weatherDesc>
            <![CDATA[Sunny]]>
        </weatherDesc>
        <precipMM>0.0</precipMM>
    </weather>
</data>

LocalWeather class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace APISample
{
        public class LocalWeather
        {
            public Data data { get; set; }
        }

        public class Data
        {
            public List<Current_Condition> current_Condition { get; set; }
            public List<Request> request { get; set; }
            public List<Weather> weather { get; set; }
        }

        public class Current_Condition
        {
            public DateTime observation_time { get; set; }
            public DateTime localObsDateTime { get; set; }
            public int temp_C { get; set; }
            public int windspeedMiles { get; set; }
            public int windspeedKmph { get; set; }
            public int winddirDegree { get; set; }
            public string winddir16Point { get; set; }
            public string weatherCode { get; set; }
            public List<WeatherDesc> weatherDesc { get; set; }
            public List<WeatherIconUrl> weatherIconUrl { get; set; }
            public float precipMM { get; set; }
            public float humidity { get; set; }
            public int visibility { get; set; }
            public int pressure { get; set; }
            public int cloudcover { get; set; }
        }

        public class Request
        {
            public string query { get; set; }
            public string type { get; set; }
        }

        public class Weather
        {
            public DateTime date { get; set; }
            public int tempMaxC { get; set; }
            public int tempMaxF { get; set; }
            public int tempMinC { get; set; }
            public int tempMinF { get; set; }
            public int windspeedMiles { get; set; }
            public int windspeedKmph { get; set; }
            public int winddirDegree { get; set; }
            public string winddir16Point { get; set; }
            public string weatherCode { get; set; }
            public List<WeatherDesc> weatherDesc { get; set; }
            public List<WeatherIconUrl> weatherIconUrl { get; set; }
            public float precipMM { get; set; }
        }

        public class WeatherDesc
        {
            public string value { get; set; }
        }

        public class WeatherIconUrl
        {
            public string value { get; set; }
        }
}
  • Could be a number of reasons why this is failing, most likely your model doesn't match up with the XML - check the `InnerException` for the *real* issue. – James Oct 11 '13 at 14:05
  • Like James said, double-check your LocalWeather class to make sure your model matches the XML you're fetcing. Post the class here if you want another set of eyes. – Daniel Simpkins Oct 11 '13 at 14:08
  • @DanielSimpkins: I have posted the LocalWeather class. –  Oct 11 '13 at 14:13
  • @James: I have checked InnerException. Inner Exception says: "Data at the root level is invalid. Line 1, position 1." –  Oct 11 '13 at 14:16
  • Looks like it could be a [BOM issue](http://stackoverflow.com/questions/291455/xml-data-at-root-level-is-invalid). – James Oct 11 '13 at 14:23
  • @James: Thanks a lot for your effort. Later I have realized a silly mistake I have made in my original code was trying to get JSON output and trying to deserialize using XML Serializer. Now, I got another exception. It was saying " was not expected." I think xmlns values comes with XML which is not match with model class. What i need to remove XMLNS values –  Oct 11 '13 at 14:34
  • 1
    @jchoudhury you need to add `XmlRoot` attribute to the `Data` class. – James Oct 11 '13 at 14:41
  • @James: Thanks again. Actually I am trying to say, I am not creating the XML file. Actually xml file is coming from the ResponseStream of API itself. So, it really don't work out. –  Oct 11 '13 at 14:50
  • 1
    @jchoudhury doesn't matter the serializer still needs to know *how* to map the fields across. Your `Data` class will need to look like `[XmlRoot("data")]public class Data { }`, you may have to do the same with the rest as the names are case sensitive so `request` in the XML won't match `Request`... – James Oct 11 '13 at 14:55
  • @James: Already did, but it is not helping the issue by the way. I dont know, where is the problem. –  Oct 11 '13 at 15:08

2 Answers2

1

You need to update the class to match the schema of the XML structure (these are case sensitive).

You can start with your existing file using the attributes found in System.Xml.Serialization.

[XmlRoot("data")]
public class Data { 
// and so on..
}

Or you could use the XSD tool to generate the class for you following these steps.

  1. Create schema for the XML returns from the service (Xml -> Create Schema)
  2. In VS Studio tools run this command: XSD XmlSchema.xsd /c (where XmlSchema.xsd is the schema produced in step 1).
PeterB
  • 1,864
  • 1
  • 12
  • 9
0

The way that your model is set up right now, you have LocalWeather as the root, whereas in the actual XML the root is Data. That's why you're getting the "Invalid root node" error. So, instead of

XmlSerializer des = new XmlSerializer(typeof(LocalWeather));
StreamReader tr = new StreamReader(result);
Object obj = des.Deserialize(tr);
LocalWeather data = (LocalWeather)obj;

try

XmlSerializer des = new XmlSerializer(typeof(Data));
StreamReader tr = new StreamReader(result);
Object obj = des.Deserialize(tr);
Data data = (Data)obj;
Daniel Simpkins
  • 674
  • 5
  • 18