Answered IEnumerable's foreach does not work in this code

aricherie

New member
Joined
Feb 10, 2021
Messages
3
Programming Experience
1-3
Hi all, I need to extract coordinates from an XML file (specifically a KML file). I used IEnumerable to search for all tags with "coordinates" but nothing at all prints out in the "foreach" loop. Can someone guide me what is incorrect here? Here is a test kml file to help: hastebin.

C#:
            XDocument kmlDoc = XDocument.Load("Documents\\c#\\SafeFlyZone.kml");
            IEnumerable<XElement> coordinates = kmlDoc.Elements("coordinates") ;
            
            foreach (XElement c in coordinates)
            {
                Console.WriteLine(c);
                Console.WriteLine("hi");
            }
 
Last edited by a moderator:
Did you debug your code, i.e. set a breakpoint and step through the code? If you haven't, go back and do it. If you have, tell us what happened. If execution gets to the foreach line but doesn't get into the loop then there's no items in the list, plain and simple.
 
Part of the problem here is that you are using Elements() which just returns matching nodes that are direct children of the parent node. Looking at the KML file you have in hastebin, the <coordinates> node is several levels deep. Perhaps you meant to use [icodeDescendants()[/icode]?
 
Part of the problem here is that you are using Elements() which just returns matching nodes that are direct children of the parent node. Looking at the KML file you have in hastebin, the <coordinates> node is several levels deep. Perhaps you meant to use [icodeDescendants()[/icode]?
Hey,
I updated to code to use Descendants.

C#:
           XDocument kmlDoc = XDocument.Load("C:\\Users\\ari.paterson.CGW\\Documents\\c#\\SafeFlyZone.kml");
            IEnumerable<XElement> coordinates = kmlDoc.Descendants() ;
         
            foreach (XElement c in coordinates)
            {
                Console.WriteLine(c);
            }
The issue is that if I specify the "coordinates" tag within the Descendants parameter, ie. changing the line to this: IEnumerable<XElement> coordinates = kmlDoc.Descendants("coordinates") ;
then the foreach loop does not display anything.
 
Last edited:
Recall that your .KML file makes use of XML namespaces, so you need to qualify the XNames that you pass in with namespaces.

Anyway, the following code works for me:
C#:
var xdoc = XDocument.Load("SafeFlyZone.kml");
var coordinates = xdoc.Descendants("{http://www.opengis.net/kml/2.2}coordinates");
foreach(var c in coordinates)
    Console.WriteLine(c);
 
Recall that your .KML file makes use of XML namespaces, so you need to qualify the XNames that you pass in with namespaces.

Anyway, the following code works for me:
C#:
var xdoc = XDocument.Load("SafeFlyZone.kml");
var coordinates = xdoc.Descendants("{http://www.opengis.net/kml/2.2}coordinates");
foreach(var c in coordinates)
    Console.WriteLine(c);
Thank you. Now that it's read in properly, I need to extract the latitude, longitude, and altitude for each coordinate. I have a Coordinate class with those attributes. As you can see in that KML file, all the latitude, longitude, and altitude for each point are listed back-to-back within one coordinate tag (basically all coordinate points that, together, encompass a closed "area"). How would you advise I extract those 3 attributes for each coordinate? I want to be efficient
 
For those playing along at home and not bothering to open the hastebin (or whose corporate firewalls are blocking access to hastebin):
XML:
<coordinates>
  -81.63342996909985,26.00624888622895,5.511072327176461 -81.69436462186725,26.00111266059973,5.775688596799045 -81.72714274216864,25.97200771522702,5.891206165085467 -81.74804280929955,25.89820713561373,5.516336686554482 -81.7194878797953,25.86969159426276,5.406925156662283 -81.68777978463756,25.8678037174685,5.565123116987332 -81.64888892173191,25.89234574717341,5.847666518438936 -81.65501830196251,25.90413728541918,5.577885344879334 -81.67890577689818,25.90698854943053,5.376601784872362 -81.69497545624714,25.92429045472441,6.031950330691663 -81.62838022283984,25.91364075147099,5.399419633485818 -81.60404574616953,25.9581287386885,5.715948449035759 -81.63342996909985,26.00624888622895,5.511072327176461
</coordinates>

Personally, if I were not concerned about efficiency, I would split the InnerText value by spaces first to get each group of X,Y,Z values, and then for each group split by commas to get each X, Y, Z value and then parse the floating point values into properties of the Coordinate class. I would ignore the cost of allocating all the arrays and strings created by each parsing process, and the overhead of using a class instead of struct.

If I were concerned about efficiency, I would first ensure that the Coordinate class is converted to a Coordinate struct. Next, I would write a custom parser that would parse the string from left to write consuming the X, Y, Z values as it encounters them and spits out Coordinate structs as each one is completely read in.
 
Back
Top Bottom