2015-12-27 5 views
1

Я пытаюсь разобрать этот .kml файл:Perl XML :: LibXML, findnodes может читать только корень файла XML

<?xml version="1.0" encoding="utf-8" ?> 
<kml xmlns="http://www.opengis.net/kml/2.2"> 
<Document id="root_doc"> 
<Schema name="PostalCodeCanada" id="PostalCodeCanada"> 
    <SimpleField name="ZIP" type="string"></SimpleField> 
    <SimpleField name="VERTICES" type="int"></SimpleField> 
</Schema> 
<Folder><name>PostalCodeCanada</name> 
    <Placemark> 
    <Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style> 
    <ExtendedData><SchemaData schemaUrl="#PostalCodeCanada"> 
     <SimpleData name="ZIP">G1Y1B1</SimpleData> 
     <SimpleData name="VERTICES">5</SimpleData> 
    </SchemaData></ExtendedData> 
     <Polygon><altitudeMode>relativeToGround</altitudeMode><outerBoundaryIs><LinearRing><altitudeMode>relativeToGround</altitudeMode><coordinates>-73.604399,45.545611 -73.603988,45.545886 -73.602861,45.547715 -73.602861,45.547715 -73.604399,45.545611 -73.604399,45.545611</coordinates></LinearRing></outerBoundaryIs></Polygon> 
    </Placemark> 
    <Placemark> 
    <Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style> 
    <ExtendedData><SchemaData schemaUrl="#PostalCodeCanada"> 
     <SimpleData name="ZIP">G1Y1B2</SimpleData> 
     <SimpleData name="VERTICES">5</SimpleData> 
    </SchemaData></ExtendedData> 
     <Polygon><altitudeMode>relativeToGround</altitudeMode><outerBoundaryIs><LinearRing><altitudeMode>relativeToGround</altitudeMode><coordinates>-73.604399,45.545611 -73.603988,45.545886 -73.602861,45.547715 -73.602861,45.547715 -73.604399,45.545611 -73.604399,45.545611</coordinates></LinearRing></outerBoundaryIs></Polygon> 
    </Placemark> 
</Folder> 
</Document></kml> 

Я использую Perl с XML :: LibXML, но findnodes не может прочитать любой узел, кроме '/'. Вот мой код:

#!/usr/bin/env perl 

use XML::LibXML; 
use strict; 
use warnings; 

my $outputFilename = "PostalCodesCollegePro.kml"; 

my $intro = '<?xml version="1.0" encoding="utf-8" ?>'."\n".'<kml xmlns="http://www.opengis.net/kml/2.2">'."\n".'<Document id="root_doc">'."\n".'<Schema name="PostalCodeCanada" id="PostalCodeCanada">'."\n\t".'<SimpleField name="ZIP" type="string"></SimpleField>'."\n\t".'<SimpleField name="VERTICES" type="int"></SimpleField>'."\n".'</Schema>'."\n".'<Folder><name>PostalCodeCanada</name>'."\n"; 
my $outro = '</Folder>'."\n".'</Document></kml>'."\n"; 

open (my $fh, ">".$outputFilename) or die "Impossible d'ouvrir le fichier d'écriture"; 
print $fh $intro; 

my $xml = XML::LibXML->new(); 
my $data = $xml->parse_file("PostalCodeCanada.kml"); 
foreach my $node ($data->findnodes('//Folder')) { 
    print ($node->toString); 
# my($zip) = $node->findnodes('./ExtendedData/SchemaData/SimpleData'); 
# print ($zip->to_literal."\n"); 
# if ($zip->to_literal =~ /(^G1Y)|(^G3A)|(^G2G)|(^G3L)|(^G3H)|G0A2R0|G0A1T0|G0A1L0|G0A3H0|G0A3G0|G0A2Y0|G0A2Z0|G0A4N0|G0A2J0|G0A3M0|G0A4A0|G0A1A0|G0A1Y0|G0A1S0|G0A4B0|G0A3T0|G0A3B0|G0A4H0|G0A1W0|G0A3L0|G0A4L0|G0A3A0/){ 
#  print $fh $node->to_literal; 
# } 
} 

print $fh $outro; 
close $fh or warn "Impossible de fermer le fichier après écriture";` 

Спасибо всем, кто поможет! PS: Это уменьшенный файл .kml, на самом деле реальный имеет всю географическую информацию всех канадских почтовых индексов. Я пытаюсь создать еще один .kml, содержащий только нужный почтовый код, чтобы создать карту с API карт Google.

ответ

1

Ваша проблема в том, что ваши узлы находятся в пространстве имен, поэтому вам нужно иметь дело с этим. Самый простой способ - это, вероятно, использовать объект XML::LibXML::XPathContext.

my $xml = XML::LibXML->new(); 
my $data = $xml->parse_file("PostalCodeCanada.kml"); 

my $xpc = XML::LibXML::XPathContext->new($data); 
$xpc->registerNs('k', 'http://www.opengis.net/kml/2.2'); 

foreach my $node ($xpc->findnodes('//k:Folder')) { 
    ... 
} 
+0

Спасибо, я не знал, что XMLNS означает XML - пространство имен: о. – whippet

1

Данные XML используют пространство имен по умолчанию, которое должно быть указано явно при обращении к нему с использованием XPath. Где XML::LibXML обеспокоен, что означает, что вы должны создать XML::LibXML::XPathContext объект для поиска данных

Вот пример программы, которая делает то, что вам нужно

#!/usr/bin/env perl 

use strict; 
use warnings; 

use XML::LibXML; 

my $doc = XML::LibXML->load_xml(location => 'PostalCodeCanada.kml'); 
my $xpc = XML::LibXML::XPathContext->new($doc); 
$xpc->registerNs(gis => 'http://www.opengis.net/kml/2.2'); 

for my $folder ($xpc->findnodes('/gis:kml/gis:Document/gis:Folder')) { 

    my ($zip) = $xpc->findnodes('gis:Placemark/gis:ExtendedData/gis:SchemaData/gis:SimpleData', $folder); 
    $zip = $zip->to_literal; 

    print "$zip\n"; 

    if ($zip =~ /(?:G0A(?:1A0|1L0|1S0|1T0|1W0|1Y0|2J0|2R0|2Y0|2Z0|3A0|3B0|3G0|3H0|3L0|3M0|3T0|4A0|4B0|4H0|4L0|4N0)|G1Y|G1Y1B1|G2G|G3A|G3H|G3L)/){ 
     print $folder->to_literal; 
    } 
} 
0

У вас уже есть ответ изнутри XML::LibXML. Однако я укажу - если вы используете XML::Twig, вы можете игнорировать пространство имен. (Это потому, что на самом деле не поддерживает их - это хорошо, если вы получили только один!)

Смежные вопросы