Search code examples
c#xmlgpsxmlreadergpx

C# XMLreader, not going into if statement to read element


I have a C# program that reads a gpx file, I place every element in a variable and at the end I put all thos element in an object. for al these elements I have functions, so each function reads a tag, I do that with this if statement:

        public double GetEle(XmlReader reader)
    {

            if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "ele"))
            {
                MessageBox.Show(Convert.ToString(reader.ReadElementContentAsDouble()));
                double value = reader.ReadElementContentAsDouble();
                return Math.Round(value, 2);
            }
        return 0;
    }

the problem is that my program never goes into that if statement (my messageBox doesn't pop up) however if I place that if statement inside this loop ↓ . Then my program goes into all my if statement.

                while (reader.Read())
            {}

My problem is that I use while (reader.Read()) in the function that calls my GetEle() function. So I don't want to loop throught my GetEle() function, only run it one time:

        public List<GPXDataObject> Extract(string path)
    {
        if (path == String.Empty)
        {
            throw new ArgumentOutOfRangeException("path");
        }
        if (path == null)
        {
            throw new ArgumentNullException("path");
        }
        List<GPXDataObject> gpxDataList = new List<GPXDataObject>();

        using (XmlReader reader = XmlReader.Create(path))
        {
            while (reader.Read())
            {
                List<double> coordinates = Coordinates(reader);
                double lat = coordinates[0];
                double lon = coordinates[1];
                double ele = GetEle(reader);
                DateTime date = GetDate(reader);
                float speed = GetSpeed(reader);
                float azimuth = GetAzimuth(reader);
                GPXDataObject gpxDataObject = new GPXDataObject(lat, lon, ele, date, speed, azimuth);
                gpxDataList.Add(gpxDataObject);
            }
            reader.Close();
        }
        return gpxDataList;
    }

I have this problem in all my functions, if I use while(reader.read()) the function works, but loops throught my whole gpx file and returns the last element. If I don't include the while loop my program never goes into my if statement.

  • why doesn't my GetEle function work without the while loop? (I have the while loop in my main function)
  • How to fix it?

Here is a sample of my xml data:

<trk>
<trkseg>
    <trkpt lat="47.021897" lon="9.965247">
        <ele>811.90</ele>
        <time>2015-02-18T07:17:25.01Z</time>
        <extensions>
            <gte:gps speed="2.1" azimuth="42.9"/>
        </extensions>
    </trkpt>
    <trkpt lat="47.021896" lon="9.965999">
        <ele>812.19</ele>
        <time>2015-02-18T07:17:25.21Z</time>
        <extensions>
            <gte:gps speed="2.0" azimuth="44.3"/>
        </extensions>
    </trkpt>
    <trkpt lat="47.021890" lon="9.965241">
        <ele>812.53</ele>
        <time>2015-02-18T07:17:25.41Z</time>
        <extensions>
            <gte:gps speed="1.5" azimuth="48.0"/>
        </extensions>
    </trkpt>
    <trkpt lat="47.021885" lon="9.965238">
        <ele>812.49</ele>
        <time>2015-02-18T07:17:25.61Z</time>
        <extensions>
            <gte:gps speed="1.2" azimuth="58.7"/>
        </extensions>
    </trkpt>
</trkseg>

I hope I explained my problem clear enough and someone will take the time to read through it and help me. :D


Solution

  • XmlReader is forward-only reading, and it only advances when you call .Read() - so here's what your program is currently doing (assuming the Coordinates constructor that takes an XmlReader is meant to parse the trkpt element):

    1. Create Reader for the file
    2. For every single node (element, text, attribute) in the file, run the code that tries to get coordinates, elements, and create your GPXDataObject.
    3. Return a list of these partial GPXDataObjects (one loop got lat/long, one loop got speed, one loop got time, etc.).

    Here's more along the lines of what you probably want:

    using (XmlReader reader = XmlReader.Create(path))
    {
        reader.MoveToContent();
        while (reader.ReadToFollowing("trkpt")) // advance the reader to the next trkpt element
        {
            List<double> coordinates = Coordinates(reader);
            double lat = coordinates[0];
            double lon = coordinates[1];
            reader.ReadToFollowing("ele"); // reader.Read() might work here, depending on what state Coordinates left the reader in
            double ele = GetEle(reader);
            reader.ReadToFollowing("time");
            DateTime date = GetDate(reader);
            reader.ReadToFollowing("extensions"); // note: it's not clear what GetSpeed and GetAzimuth need - do they expect the reader to be on the extensions element or the gte:gps element?
            float speed = GetSpeed(reader);
            float azimuth = GetAzimuth(reader);
            GPXDataObject gpxDataObject = new GPXDataObject(lat, lon, ele, date, speed, azimuth);
            gpxDataList.Add(gpxDataObject);
        }         
    }
    

    That should at least get you started.