Извлечь данные из xml-файла

У меня есть файл xml, содержащий тысячи записей, например:

<gml:featureMember>
<Feature>
<featureType>JCSOutput</featureType>
<property name="gml2_coordsys"></property>
<gml:PointProperty>
                <gml:Point>
                  <gml:coordinates>4048313.294966287,5374397.792158723 </gml:coordinates>
                </gml:Point>

</gml:PointProperty>
<property name="BEZEICHNUN">Anton-Bosch-Gasse</property>
<property name="WL_NUMMER">68</property>
</Feature>
</gml:featureMember>


<gml:featureMember>
<Feature>
<featureType>JCSOutput</featureType>
<property name="gml2_coordsys"></property>
<gml:PointProperty>
                <gml:Point>
                  <gml:coordinates>4044355.0231338665,5365146.95116724 </gml:coordinates>
                </gml:Point>

</gml:PointProperty>
<property name="BEZEICHNUN">Anschützgasse</property>
<property name="WL_NUMMER">67</property>
</Feature>
</gml:featureMember>

Скрипт должен искать имя, указанное в списке (например, Антон-Бош-Гассе), и копировать весь абзац, начинающийся с <gml:featureMember>, в новый файл.

Что бы вы использовали для этой цели — awk, sed, perl?


person Ulrich Flamm    schedule 29.03.2013    source источник


Ответы (3)


Использование xml_grep, которое поставляется с XML::Twig, вы можете написать

$ xml_grep --root 'gml:featureMember' \
--cond 'property[string()="Anton-Bosch-Gasse"]' \
to_grep.xml > extract.xml
person mirod    schedule 29.03.2013
comment
большое спасибо, я использовал ваше решение, для меня это проще всего реализовать :-) - person Ulrich Flamm; 30.03.2013

Sed и awk не подходят для разбора XML. Достичь Perl:

#!/usr/bin/perl
use warnings;
use strict;

use XML::LibXML;

my $search = 'Anton-Bosch-Gasse';

# Put your real values here!
my $file = '1.xml';
my $uri  = 'http://1.2.3';

my $xpc = XML::LibXML::XPathContext->new;
$xpc->registerNs('gml', $uri);

my $xml = XML::LibXML->load_xml(location => $file);
my $r = $xml->find("//property[.='$search']/ancestor::gml:featureMember");
print $_->serialize for @$r;

Или, если приведенный выше пример кажется вам слишком многословным, вы можете использовать xsh:

my $search = 'Anton-Bosch-Gasse' ;
register-namespace gml http://1.2.3 ; # Insert the real URI.
open 1.xml ;                          # Insert the real path.
ls //property[.=$search]/ancestor::gml:featureMember ;
person choroba    schedule 29.03.2013

Вот решение, похожее на choroba, но использующее пакет Mojolicious. Его модуль Mojo::DOM просматривает XML, используя селекторы css3, а не xpath.

Здесь я сначала нахожу все элементы gml:featureMember, а затем извлекаю первый элемент, у которого есть соответствующий потомок.

#!/usr/bin/env perl

use strict;
use warnings;

use Mojo::DOM;
use Mojo::Util qw/slurp spurt/;

my $dom = Mojo::DOM->new->xml(1);

# read in from file
# $dom->parse( slurp 'myfile.xml' );
# but for the demo ...
$dom->parse(do{ local $/; <DATA> });

my $found = 
  $dom->find('gml\:featureMember')
      ->first(sub{ 
        $_->find('property[name="BEZEICHNUN"]')
          ->first( qr/\QAnton-Bosch-Gasse/ )
      });

spurt "$found", 'output.xml';


__DATA__
<gml:featureMember>
<Feature>
<featureType>JCSOutput</featureType>
<property name="gml2_coordsys"></property>
<gml:PointProperty>
                <gml:Point>
                  <gml:coordinates>4048313.294966287,5374397.792158723 </gml:coordinates>
                </gml:Point>

</gml:PointProperty>
<property name="BEZEICHNUN">Anton-Bosch-Gasse</property>
<property name="WL_NUMMER">68</property>
</Feature>
</gml:featureMember>


<gml:featureMember>
<Feature>
<featureType>JCSOutput</featureType>
<property name="gml2_coordsys"></property>
<gml:PointProperty>
                <gml:Point>
                  <gml:coordinates>4044355.0231338665,5365146.95116724 </gml:coordinates>
                </gml:Point>

</gml:PointProperty>
<property name="BEZEICHNUN">Anschützgasse</property>
<property name="WL_NUMMER">67</property>
</Feature>
</gml:featureMember>

Для этого примера я беру XML из раздела DATA. Вы можете использовать закомментированный код для анализа файла.

Вы также можете быть немного более эффективным, если вы уверены, что свойство постоянно находится в глубине структуры.

my $found = 
  $dom->find('gml\:featureMember property[name="BEZEICHNUN"]')
      ->first( qr/\QAnton-Bosch-Gasse/ )
      ->parent
      ->parent;
person Joel Berger    schedule 29.03.2013