1

I have a class which defines meteorological measurements with an API. I have created classes to store these measurements within an XML file. I have been able to write to the XML file, but am unable to read from it. I need to be able to read the data, then instantiate the Measurement Class via the constructor, and then add these instances to a List Here is the code for the Measurement constructor

  public Measurement(string longit, string latitud, string cty, string pcode, DateTime dte, decimal huy, decimal pre, string windDir, int windSp) : base(longit, latitud, cty,pcode)
    {

        dte = date;
        huy = humidity;
        pre = precipitation;           
        windDir = windDirection;
        windSp = windSpeed;
    }

and here is a sample of the XML file

<Measurement>
<longitude>-76.2858726</longitude>
<latitude>36.8507689</latitude>
<city>Thetford</city>
<postcode>IP24 1ED</postcode>
<date>01/04/2011</date>
<windDirection>SE</windDirection>
<windSpeed>8</windSpeed>
<humidity>2.6</humidity>
<precipitation>0.0</precipitation>
</Measurement>

And here is the method I have written to read the file, and make an instance of the class Measurement. I receive no errors, however have not managed to create the List<>

public List<Measurement> GetList()
    {
        List<Measurement> measurements = new List<Measurement>();
        XDocument doc = XDocument.Load(@"C:\Users\Sonya\Documents\Visual Studio 2010\Projects\WeatherAPI\WeatherAPI\measurement_store.xml");
        XElement root = doc.Root;

     var d = (from s in root.Descendants("Measurement")
                 select new Measurement
                 {
                     Longitude = s.Element("longitude").Value,
                     Latitude = s.Element("latitude").Value,
                     City = s.Element("city").Value,
                     Postcode = s.Element("postcode").Value,
                     Date = DateTime.Parse(s.Element("date").Value),
                     Humidity = decimal.Parse(s.Element("humidity").Value),
                     Precipitation = decimal.Parse(s.Element("precipitation").Value),
                     WindSpeed = Convert.ToInt32(s.Element("windSpeed").Value),
                     WindDirection = s.Element("windDirection").Value,

                 }).ToList();


     d.ForEach(measurements.Add);

        return measurements;
    }//end GetList()

I've also written another method, of a slightly different format..

public List<Measurement> createXMLListMeasurements()
    {
        //load the xml document
        XDocument doc = XDocument.Load(@"C:\Users\Sonya\Documents\Visual Studio 2010\Projects\WeatherAPI\WeatherAPI\measurement_store.xml");
        //XElement root = doc.Root;

        //instantiate a new list of measurements
        List<Measurement> measurements = new List<Measurement>();

            //get a list of measurement elements
           var d = from s in doc.Descendants("Measurement")
                    //where
                    select new 
                    { //assign Measurement variables to data from xml doc
                        Longitude = (string)s.Element("longitude").Value,
                        Latitude = (string)s.Element("latitude").Value,
                        City = (string)s.Element("city").Value,
                        Postcode = (string)s.Element("postcode").Value,
                        Date = DateTime.Parse(s.Element("date").Value),
                        Humidity = decimal.Parse(s.Element("humidity").Value),
                        Precipitation = decimal.Parse(s.Element("precipitation").Value),
                        WindSpeed = Convert.ToInt32(s.Element("windSpeed").Value),
                        WindDirection = (string)s.Element("windDirection").Value,
                    };

           foreach (var s in d)
           {   //for each element found, instantiate Measurements class, and add to the measurements list.
               Measurement m = new Measurement(s.Longitude, s.Latitude, s.City, s.Postcode, s.Date, s.Humidity, s.Precipitation, s.WindDirection, s.WindSpeed);
               measurements.Add(m);

           }


        return measurements;
    }

Apologies if these questions seem silly, am VERY new to LINQ and XML, so finding my way very slowly..any help much appreciated! A console application calls this method for testing and produces nothing but WeatherAPI.Measurement WeatherAPI.Measurement

Help? thanks!

3
  • sorry the XML hasn't rendered here properly..the end tag of the Measurement element is missing.. </Measurement>. Thanks! Commented Apr 3, 2011 at 17:56
  • Why are you creating a new List<T> and then calling Add on it each time in GetList? Just return d... It would be very helpful if you could provide a short but complete program which demonstrates the problem it doesn't need all the properties - just a couple would be fine. Commented Apr 3, 2011 at 18:02
  • From a cursory glance at your code, it looks fine - what's the problem exactly? No measurement objects are read from the xml file? Commented Apr 3, 2011 at 18:02

1 Answer 1

1

Overall, your code looks fine. As Jon Skeet pointed out in his comment, you don't need to bother adding each element to a list -- you can simply return the result of the query after calling .ToList().

Most likely, there's either something wrong with your xml file, or you're reading it incorrectly.

If your xml file is truly just:

<Measurement>
    <longitude>-76.2858726</longitude>
    <latitude>36.8507689</latitude>
    <city>Thetford</city>
</Measurement>

Then your code won't work, because the root of the xml file is Measurement. Therefore, calling doc.Root.Descendants("Measurement") will give you 0 results. Instead, your xml file should have a unique root element, for example:

<root>
    <Measurement>
        <longitude>-76.2858726</longitude>
        <latitude>36.8507689</latitude>
        <city>Thetford</city>
    </Measurement>
    <Measurement>
        <longitude>-71.2858726</longitude>
        <latitude>32.1507689</latitude>
        <city>Other City</city>
    </Measurement>
</root>

Furthermore, you don't need to bother obtaining the Root of the xml document. If all you want to do is find elements named Measurement, just say doc.Descendants("Measurement").

Try this code with the above xml file:

void Main()
{
    var measurements = GetMeasurements(@"C:\path\to\file\measurements.xml");
}

public List<Measurement> GetMeasurements(string path)
{
    XDocument doc = XDocument.Load(path);

    return (from s in doc.Descendants("Measurement")
            select new Measurement
            {
                 Longitude = Convert.ToDecimal(s.Element("longitude").Value),
                 Latitude = Convert.ToDecimal(s.Element("latitude").Value),
                 City = s.Element("city").Value,
            }).ToList();
}

public class Measurement
{
    public decimal Longitude { get; set; }
    public decimal Latitude { get; set; }
    public string City { get; set; }
}

When I run it in LINQPad, I get the following result:

sample result

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Pandicus, I've run the above code exactly and still get the same result, a console window showing "WeatherAPI.Measurement". I did have a root to the document before, <Measurements> being the root, <Measurement> being the descendant. Any more thoughts? Thanks so much!!
@Pandicus, Thank you so much, fixed it, was having a bit of a blonde moment.. wasn't displaying my result properly, but after I stopped trying to add a list to a list all worked out fine. Thanks again!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.