2013-06-21 3 views
4

Я пытаюсь разобрать файл KML с помощью perl. Я пытаюсь использовать модуль XML::Simple для этого.Как анализировать файлы KML с помощью perl?

Я хочу, чтобы пройти через каждый placemarker и извлечь некоторые данные, а именно

1) MCODE
2) координаты

После прочтения нескольких постов, я попытался следующие просто напечатать координаты всех точек , но она не

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"; 
} 

Я использую следующие 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> 

ответ

3

Как насчет:

while (my ($key, $folder) = each %{$myFile->{Document}{Folder}{Placemark}}) { 
    print $folder->{Point}->{coordinates}."\n"; 
} 

выход:

80.2437973022461,13.106230102044576,0.0 
80.24688720703125,13.096198508196448,0.0 
80.23435592651367,13.094024942328286,0.0 

В вашем коде, вы используете

foreach my $folder (@{$myFile->{Document}->{Folder}->{Placemark}}) { 
    print $folder->{Point}->{coordinates}."\n"; 
} 

предполагая $myFile->{Document}->{Folder}->{Placemark} является ссылкой на массив. Но это не так, это ссылка на хеш, поэтому вам нужно пройти через него, а пара foreach (key, value) извлечь координату из значения.

+0

Это работало как волшебство. Пожалуйста, объясните свой ответ! – bubble

+0

@bubble: см. Мой обновленный ответ. – Toto

3

Я не думаю, что использовал бы XML :: Simple для этого.

с XML :: Twig это то, что можно было бы написать:

#!/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]); 
0

Другая возможность заключается в использовании XML::LibXML и XPaths. Преимущество XPaths в том, что они также доступны для других языков, поэтому другой разработчик может понять ваш код. Недостатком XPaths является то, что их использование не является более приятным в присутствии пространств имен (что здесь имеет место), что приводит к некоторым уродливым обходным решениям, например, с использованием функции local-name().

Вот пример сценария:

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"; 
}