问题
I am trying to parse a KML file using perl. I am trying to use XML::Simple
module for doing this.
I want to go through each placemarker and extract some data namely
1) Mcode
2) coordinates
After reading several posts, I tried the following just to print the coordinates of all the points, but it fails
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
my $myFile = XMLin('ExperimentMap.kml');
foreach my $folder (@{$myFile->{Document}->{Folder}->{Placemark}}) {
print $folder->{Point}->{coordinates}."\n";
}
I am using the following KML:
<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'>
<Document>
<name>ExperimentMap</name>
<description><![CDATA[]]></description>
<Folder>
<name>ExperimentLayer</name>
<Placemark>
<styleUrl>#icon-503-FF8277</styleUrl>
<name>home</name>
<ExtendedData>
<Data name='string'>
<displayName>Mcode</displayName>
<value>PLAAB</value>
</Data>
</ExtendedData>
<ExtendedData>
<Data name='string'>
<displayName>postal code</displayName>
<value>450010</value>
</Data>
</ExtendedData>
<description><![CDATA[my home
Mcode: PLAAB
postal code: 450010]]></description>
<Point>
<coordinates>80.23435592651367,13.094024942328286,0.0</coordinates>
</Point>
</Placemark>
<Placemark>
<styleUrl>#icon-503-FF8277</styleUrl>
<name>shop</name>
<ExtendedData>
<Data name='string'>
<displayName>Mcode</displayName>
<value>XMPLE</value>
</Data>
</ExtendedData>
<ExtendedData>
<Data name='string'>
<displayName>postal code</displayName>
<value>450013</value>
</Data>
</ExtendedData>
<description><![CDATA[my shop
Mcode: XMPLE
postal code: 450013]]></description>
<Point>
<coordinates>80.2437973022461,13.106230102044576,0.0</coordinates>
</Point>
</Placemark>
<Placemark>
<styleUrl>#icon-503-FF8277</styleUrl>
<name>place3</name>
<ExtendedData>
<Data name='string'>
<displayName>Mcode</displayName>
<value>UDKBL</value>
</Data>
</ExtendedData>
<ExtendedData>
<Data name='string'>
<displayName>postal code</displayName>
<value>578635</value>
</Data>
</ExtendedData>
<description><![CDATA[my school
Mcode: UDKBL
postal code: 578635]]></description>
<Point>
<coordinates>80.24688720703125,13.096198508196448,0.0</coordinates>
</Point>
</Placemark>
</Folder>
<Style id='icon-503-FF8277'>
<IconStyle>
<color>ff7782FF</color>
<scale>1.1</scale>
<Icon>
<href>http://www.gstatic.com/mapspro/images/stock/503-wht-blank_maps.png</href>
</Icon>
</IconStyle>
</Style>
</Document>
</kml>
回答1:
How about:
while (my ($key, $folder) = each %{$myFile->{Document}{Folder}{Placemark}}) {
print $folder->{Point}->{coordinates}."\n";
}
output:
80.2437973022461,13.106230102044576,0.0
80.24688720703125,13.096198508196448,0.0
80.23435592651367,13.094024942328286,0.0
In your code, you're using
foreach my $folder (@{$myFile->{Document}->{Folder}->{Placemark}}) {
print $folder->{Point}->{coordinates}."\n";
}
assuming $myFile->{Document}->{Folder}->{Placemark}
is a reference to an array. But it isn't, it is a reference to a hash, so you have to walk thru it and foreach pair of (key,value) extract the coordinate from the value.
回答2:
I don't think I would use XML::Simple for this.
With XML::Twig this is what you would write:
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.0; # to get 'say'
use XML::Twig;
XML::Twig->new( twig_roots => { coordinates => sub { say $_->text; } })
->parsefile( $ARGV[0]);
回答3:
Another possibility is to use XML::LibXML
and XPaths. The advantage of XPaths is that these are also available to other languages, so other developer may understand your code. The disadvantage of XPaths is that their usage is not anymore nice in presence of namespaces (which is the case here), leading to some ugly-looking workarounds like using the local-name() function.
Here's a sample script:
use XML::LibXML;
my $doc = XML::LibXML->new->parse_file('ExperimentMap.kml');
for my $coordinate_node ($doc->findnodes('//*[local-name()="coordinates"]')) {
print $coordinate_node->textContent, "\n";
}
来源:https://stackoverflow.com/questions/17231031/how-to-parse-kml-files-using-perl