|
-
August 26th, 2009, 04:23 AM
#1
Reading XML documents in C#
Hi Everyone,
Im currently developing a weather application that forecats weather etc...I have ran into a problem with the reading of the XML feed that im using.
Here is an example of an XML feed that is being used:
<?xml version="1.0" ?>
- <weatherdata>
- <weather weatherlocationcode="wc:UKXX0085" weatherlocationname="London, GBR" zipcode="" encodedlocationname="London%2c+GBR" url="http://weather.msn.com/local.aspx?wealocations=wc:UKXX0085&q=London%2c+GBR" imagerelativeurl="http://blst.msn.com/as/wea3/i/en-us/" degreetype="F" provider="Foreca" attribution="Data provided by Foreca" attribution2="© Foreca" lat="51.5178591" long="-0.1022164" timezone="1" alert="">
<current temperature="64" skycode="32" skytext="Clear" date="2009-08-26" day="Wednesday" shortday="Wed" observationtime="09:50:00" observationpoint="London / Heathrow Airport" feelslike="64" humidity="77" windspeed="14" winddisplay="14 mph S" />
<forecast low="61" high="70" skycodeday="11" skytextday="Showers" date="2009-08-26" day="Wednesday" shortday="Wed" precip="80" />
<forecast low="54" high="74" skycodeday="30" skytextday="Partly Cloudy" date="2009-08-27" day="Thursday" shortday="Thu" precip="40" />
<forecast low="50" high="65" skycodeday="39" skytextday="Showers / Clear" date="2009-08-28" day="Friday" shortday="Fri" precip="75" />
<forecast low="49" high="68" skycodeday="28" skytextday="PM Clouds" date="2009-08-29" day="Saturday" shortday="Sat" precip="5" />
<forecast low="59" high="67" skycodeday="30" skytextday="Cloudy / PM Sun" date="2009-08-30" day="Sunday" shortday="Sun" precip="10" />
<toolbar timewindow="60" minversion="1.0.1965.0" />
</weather>
</weatherdata>
Hopefully you can make it out but for each day of the forecast the same element name is used, in this case <forecast>. The problem im having is when i read in the data from the forecast element it seems to only bring back the first instance and last instance of the forecast elements. so effectively im able to get todays weather and the weather 4 days from now as thats the last entry. I use the following code in my application:
else if ((reader.NodeType == XmlNodeType.Element) && ((reader.Name == "forecast")
&& (firstForecastDone == false)))
{
firstForecastDone = true;
reader.MoveToAttribute("high");
int.TryParse(reader.Value, out MaxTemp);
currentWeatherReport.MaxTemperatureForecast = MaxTemp;
reader.MoveToAttribute("low");
int.TryParse(reader.Value, out MinTemp);
currentWeatherReport.MinTemperatureForecast = MinTemp;
reader.MoveToAttribute("day");
currentWeatherReport.Day1 = reader.Value;
I then repeat this code incrementing the values by 1 hoping that it would simply move to the next instance of the forecast element giving me the next days weather but it does not, as i mentioned it only brings back the current days weather and the weather 4 days from now.
Does anyone know how i might code this so that its possible to read each element seperately?
-
August 26th, 2009, 07:04 AM
#2
Re: Reading XML documents in C#
Try to put the code in the tags for better readibility and also put the code where you are incrementing the counter.
-
August 26th, 2009, 08:24 AM
#3
Re: Reading XML documents in C#
This is the code I have so far far for my weather report:
Code:
public WeatherReport.WeatherReport GetWeatherReport(string location)
{
WeatherReport.WeatherReport currentWeatherReport = new WeatherReport.WeatherReport();
// URL corresponding to the MSN REST Web Service - see how the locationCode
// is passed in parameter to this URL.
// The XMLTextReader opens up the URL and receives the XML returned by th server
// http://weather.service.msn.com/data.aspx?src=vista&wealocations=wc:USWA0367
string feedUrl = "http://weather.service.msn.com/data.aspx?src=vista&wealocations=" + location;
XmlTextReader reader = new XmlTextReader(feedUrl);
bool firstForecastDone = false;
string skyImagesRelativeUrl = "Images/";
int MaxTemp, MinTemp, CurrentTemp, FeelsLike, Humidity, SkyCode, SkyCode4, MaxTemp4, MinTemp4, Precip4;
try
{
while (reader.Read())
{
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "weather"))
{
reader.MoveToAttribute("weatherlocationname");
currentWeatherReport.Location = reader.Value;
reader.MoveToAttribute("lat");
currentWeatherReport.Lattitude = reader.Value;
reader.MoveToAttribute("long");
currentWeatherReport.Longitude = reader.Value;
}
else if ((reader.NodeType == XmlNodeType.Element) && ((reader.Name == "forecast")
&& (firstForecastDone == false)))
{
firstForecastDone = true;
reader.MoveToAttribute("high");
int.TryParse(reader.Value, out MaxTemp);
currentWeatherReport.MaxTemperatureForecast = MaxTemp;
reader.MoveToAttribute("low");
int.TryParse(reader.Value, out MinTemp);
currentWeatherReport.MinTemperatureForecast = MinTemp;
reader.MoveToAttribute("day");
currentWeatherReport.Day1 = reader.Value;
}
else if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "forecast"))
{
reader.MoveToAttribute("day");
currentWeatherReport.Day4 = reader.Value;
reader.MoveToAttribute("skytextday");
currentWeatherReport.SkyText4 = reader.Value;
reader.MoveToAttribute("high");
int.TryParse(reader.Value, out MaxTemp4);
currentWeatherReport.MaxTemperatureForecast4 = MaxTemp4;
reader.MoveToAttribute("low");
int.TryParse(reader.Value, out MinTemp4);
currentWeatherReport.MinTemperatureForecast4 = MinTemp4;
reader.MoveToAttribute("precip");
int.TryParse(reader.Value, out Precip4);
currentWeatherReport.Precipitation4 = Precip4;
reader.MoveToAttribute("skycodeday");
int.TryParse(reader.Value, out SkyCode4);
currentWeatherReport.SkyCode4 = SkyCode4;
string fileName = skyImagesRelativeUrl + currentWeatherReport.SkyCode4 + ".gif";
currentWeatherReport.SkyImage4 = new Bitmap(fileName);
}
else if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "forecast"))
{
reader.MoveToAttribute("day");
currentWeatherReport.Day3 = reader.Value;
}
else if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "current"))
{
reader.MoveToAttribute("temperature");
int.TryParse(reader.Value, out CurrentTemp);
currentWeatherReport.CurrentTemperature = CurrentTemp;
reader.MoveToAttribute("feelslike");
int.TryParse(reader.Value, out FeelsLike);
currentWeatherReport.FeelsLikeTemperature = FeelsLike;
reader.MoveToAttribute("humidity");
int.TryParse(reader.Value, out Humidity);
currentWeatherReport.Humidity = Humidity;
reader.MoveToAttribute("skytext");
currentWeatherReport.SkyText = reader.Value;
reader.MoveToAttribute("skycode");
int.TryParse(reader.Value, out SkyCode);
currentWeatherReport.SkyCode = SkyCode;
string fileName = skyImagesRelativeUrl + currentWeatherReport.SkyCode + ".gif";
currentWeatherReport.SkyImage = new Bitmap(fileName);
reader.MoveToAttribute("observationtime");
char[] splitter = ":".ToCharArray();
string[] hourMinuteSecond = reader.Value.Split(splitter);
int hour, minute, second;
int.TryParse(hourMinuteSecond[0], out hour);
int.TryParse(hourMinuteSecond[1], out minute);
int.TryParse(hourMinuteSecond[2], out second);
reader.MoveToAttribute("date");
splitter = "-".ToCharArray();
string[] yearMonthDay = reader.Value.Split(splitter);
int year, month, day;
int.TryParse(yearMonthDay[0], out year);
int.TryParse(yearMonthDay[1], out month);
int.TryParse(yearMonthDay[2], out day);
currentWeatherReport.LastUpdate = new DateTime(year, month, day, hour, minute, second);
reader.MoveToAttribute("winddisplay");
currentWeatherReport.WindDisplay = reader.Value;
reader.MoveToAttribute("observationpoint");
currentWeatherReport.Observation = reader.Value;
}
}
return currentWeatherReport;
}
catch (Exception ex)
{
throw ex;
}
}
Im simply adding new variables myself such as Day1, Day2 etc. I know there is a way to goto the next attribute but is there a way to go to the next element or something like that. Would have been much easier if the name of the elements were different.
-
August 26th, 2009, 09:23 AM
#4
Re: Reading XML documents in C#
I woud use Xpath to select the correct XmlNodes. When you have done that, you can simply loop through the XmlNodeList
Try next
Code:
XmlDocument doc = new XmlDocument();
doc.Load("http://weather.service.msn.com/data.aspx?src=vista&wealocations=wc:USWA0367");
XmlNodeList forecast_list = doc.DocumentElement.SelectNodes("weather/forecast");
foreach (XmlNode forecast in forecast_list) {
string day = forecast.Attributes["day"].Value;
}
-
August 26th, 2009, 09:42 AM
#5
Re: Reading XML documents in C#
Ok ok, I like your thinking. This does work and it brings back each day. How would I then store each of these values.
I.e the first value it returns I want to be stored as Day1 and then the next value would be stored as Day2 etc until it has no more attributes to store.
-
August 26th, 2009, 09:44 AM
#6
Re: Reading XML documents in C#
can you post the code how your WeatherReport class looks like?
-
August 26th, 2009, 10:08 AM
#7
Re: Reading XML documents in C#
This is what i currently have in my WeatherReport class looks like:
Code:
namespace WeatherReport
{
public class WeatherReport
{
private int currentTempValue;
public int CurrentTemperature {
get
{
return currentTempValue;
}
set
{
currentTempValue = value;
}
}
private int feelsLikeTemperatureValue;
public int FeelsLikeTemperature
{
get
{
return feelsLikeTemperatureValue;
}
set
{
feelsLikeTemperatureValue = value;
}
}
private int humidityValue;
public int Humidity
{
get
{
return humidityValue;
}
set
{
humidityValue = value;
}
}
private DateTime lastUpdateValue;
public DateTime LastUpdate
{
get
{
return lastUpdateValue;
}
set
{
lastUpdateValue = value;
}
}
private string locationValue;
public string Location
{
get
{
return locationValue;
}
set
{
locationValue = value;
}
}
private int skyCodeValue;
public int SkyCode
{
get
{
return skyCodeValue;
}
set
{
skyCodeValue = value;
}
}
private string skyTextValue;
public string SkyText
{
get
{
return skyTextValue;
}
set
{
skyTextValue = value;
}
}
private Bitmap skyImageValue;
public Bitmap SkyImage
{
get
{
return skyImageValue;
}
set
{
skyImageValue = value;
}
}
private int minTemperatureForecastValue;
public int MinTemperatureForecast
{
get
{
return minTemperatureForecastValue;
}
set
{
minTemperatureForecastValue = value;
}
}
private int maxTemperatureForecastValue;
public int MaxTemperatureForecast
{
get
{
return maxTemperatureForecastValue;
}
set
{
maxTemperatureForecastValue = value;
}
}
private string locationCodeValue;
public string LocationCodeValue
{
get
{
return locationCodeValue;
}
set
{
locationCodeValue = value;
}
}
private string WindDisplayValue;
public string WindDisplay
{
get
{
return WindDisplayValue;
}
set
{
WindDisplayValue = value;
}
}
private string LattitudeValue;
public string Lattitude
{
get
{
return LattitudeValue;
}
set
{
LattitudeValue = value;
}
}
private string LongitudeValue;
public string Longitude
{
get
{
return LongitudeValue;
}
set
{
LongitudeValue = value;
}
}
private string ObservationValue;
public string Observation
{
get
{
return ObservationValue;
}
set
{
ObservationValue = value;
}
}
private string Day1Value;
public string Day1
{
get
{
return Day1Value;
}
set
{
Day1Value = value;
}
}
private string Day4Value;
public string Day4
{
get
{
return Day4Value;
}
set
{
Day4Value = value;
}
}
private string Day3Value;
public string Day3
{
get
{
return Day3Value;
}
set
{
Day3Value = value;
}
}
private int skyCode4Value;
public int SkyCode4
{
get
{
return skyCode4Value;
}
set
{
skyCode4Value = value;
}
}
private Bitmap skyImage4Value;
public Bitmap SkyImage4
{
get
{
return skyImage4Value;
}
set
{
skyImage4Value = value;
}
}
private string SkyText4Value;
public string SkyText4
{
get
{
return SkyText4Value;
}
set
{
SkyText4Value = value;
}
}
private int minTemperatureForecast4Value;
public int MinTemperatureForecast4
{
get
{
return minTemperatureForecast4Value;
}
set
{
minTemperatureForecast4Value = value;
}
}
private int maxTemperatureForecast4Value;
public int MaxTemperatureForecast4
{
get
{
return maxTemperatureForecast4Value;
}
set
{
maxTemperatureForecast4Value = value;
}
}
private int Precipitation4Value;
public int Precipitation4
{
get
{
return Precipitation4Value;
}
set
{
Precipitation4Value = value;
}
}
}
}
-
August 26th, 2009, 10:31 AM
#8
Re: Reading XML documents in C#
It is not really a nice way to code properties like 'Day1' to 'Day4'. What will happens if the weatherreport you recieve contains 5 days instead of 4?
I would use an List<T> to save the forecasts of each day
Code:
public class ForeCast{
public string Day{get;set;}
public int MaxTemperature{get;set;}
//and all order forecast element of one day
}
...
public class WeatherReport{
private List<ForeCast> foreCast_list = new List<ForeCast>();
public List<ForeCast> ForeCast_list {
get{ return foreCast_list; }
set { foreCast_list = value; }
}
...
XmlDocument doc = new XmlDocument();
doc.Load("http://weather.service.msn.com/data.aspx?src=vista&wealocations=wc:USWA0367");
XmlNodeList forecast_list = doc.DocumentElement.SelectNodes("weather/forecast");
WeatherReport report = new WeatherReport();
foreach (XmlNode forecast in forecast_list) {
ForeCast f = new ForeCast();
f.Day = forecast.Attributes["day"].Value;
f.MaxTemperature = Convert.ToInt32(forecast.Attributes["high"].Value);
report.ForeCast_list.Add(f);
}
}
Now you can loop through the report.ForeCast_list to show the data of each day
-
August 26th, 2009, 10:56 AM
#9
Re: Reading XML documents in C#
How do I display that data on my form?
Currently I have a number of labels on my main form which display all of the weather details using a WeatherReportBindingSource.
I would like to have each attribute binded to a label so that i can move the data around on my form.
-
August 26th, 2009, 10:58 AM
#10
Re: Reading XML documents in C#
Also the XML feed is fixed, it will only ever contain 5 forecast elements
-
August 27th, 2009, 02:07 AM
#11
Re: Reading XML documents in C#
You can use Reflection to find the correct property
Code:
WeatherReport report = new WeatherReport();
int daynumber = 1;
foreach (XmlNode forecast in forecast_list) {
PropertyInfo day = report.GetType().GetProperty("Day" + daynumber);
day.SetValue(report, forecast.Attributes["day"].Value, null);
daynumber++;
}
Now, all days (Day1, Day2 ... ) will have the correct value
-
August 27th, 2009, 02:55 AM
#12
Re: Reading XML documents in C#
Ok, does this replace the code that you gave me in the previous post? i.e. does that code replace the code below or is it used somewhere else?
Code:
WeatherReport report = new WeatherReport();
foreach (XmlNode forecast in forecast_list) {
ForeCast f = new ForeCast();
f.Day = forecast.Attributes["day"].Value;
f.MaxTemperature = Convert.ToInt32(forecast.Attributes["high"].Value);
report.ForeCast_list.Add(f);
}
-
August 27th, 2009, 03:00 AM
#13
Re: Reading XML documents in C#
 Originally Posted by InsyteMedia
Also the XML feed is fixed, it will only ever contain 5 forecast elements
I assumed you would like to use the WeatherReport class like you have it now, thus with the Day1, Day2... properties. If so, use the code form my previous post that uses Reflection.
Code:
WeatherReport report = new WeatherReport();
int daynumber = 1;
foreach (XmlNode forecast in forecast_list) {
PropertyInfo day = report.GetType().GetProperty("Day" + daynumber);
day.SetValue(report, forecast.Attributes["day"].Value, null);
daynumber++;
}
If you want to use the WeatherReport class like I suggested (with the List<ForeCast> property), then use the code you just posted
Code:
WeatherReport report = new WeatherReport();
foreach (XmlNode forecast in forecast_list) {
ForeCast f = new ForeCast();
f.Day = forecast.Attributes["day"].Value;
f.MaxTemperature = Convert.ToInt32(forecast.Attributes["high"].Value);
report.ForeCast_list.Add(f);
}
-
August 27th, 2009, 03:30 AM
#14
Re: Reading XML documents in C#
Thanks a lot for this, its much appreciated. I will give your suggestions a try and see how they work.
Thanks
-
August 27th, 2009, 08:06 AM
#15
Re: Reading XML documents in C#
Hiya, Ive ran into a problem when retreiving the min and max values from the feed now.
When using the following code you provided
Code:
PropertyInfo high = currentWeatherReport.GetType().GetProperty("MaxTemperatureForecast" + maxTempnumber);
high.SetValue(currentWeatherReport, forecast.Attributes["high"].Value, null);
maxTempnumber++;
I need to convert the value into an integer before saving the value, how can i do that. Ive tried using the convert.toint32 function but it doesnt seem to work, unless ive placed it in the wrong place. As the code is above it saves it as a string but i need an int.
Thanks
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|