2

xml に似たgpxファイルを処理しています。そのファイルの抜粋は次のとおりです。

<trkpt lat="3.1398377" lon="101.6937661">
    <ele>0.0</ele>
    <time>2013-01-01T00:00:00.000Z</time>
    <name>Position 1</name>
</trkpt>

<trkpt lat="3.1250538" lon="101.6783237">
    <ele>0.0</ele>
    <name>Position 460</name>
</trkpt>

ご覧のとおり、一部の<trkpt>要素には要素が含まれており、一部の要素には含まれて<time>いません。それを含まない要素に追加<time>するにはどうすればよいですか?<trkpt>

ファイルの読み取り中に、XML ノードに以下が含まれていない場合、エラーが発生します<time>

foreach $points ( $root->getElementsByTagName('trkpt') ) {
    my($lat)  = $points->findvalue('@lat');
    my($lon)  = $pints->findvalue('@lon');
    my($time) = $points->getElementsByTagName('time')->[0]->textContent();
    my($pointName)  = $points->getElementsByTagName('name')->[0]->textContent();
}

未定義の値でメソッド「textContent」を呼び出すことはできません...

どうすればそれをよりインテリジェントにすることができますか?つまり、 undefined が検出された場合$time<time>が gpx ファイルに書き込まれ、エラーは発生しません。

4

2 に答える 2

6

ファイルのサイズに応じて、XML::LibXMLXML ドキュメント全体をメモリに読み込む か、XML::TwigXML をストリームとして処理し、使用するメモリを最小限に抑える を使用できます。

テスト目的で<root>、入力データにルート要素を追加して、次のように整形式の XML にしました。

<root>
  <trkpt lat="3.1398377" lon="101.6937661">
    <ele>0.0</ele>
    <time>2013-01-01T00:00:00.000Z</time>
    <name>Position 1</name>
  </trkpt>
  <trkpt lat="3.1250538" lon="101.6783237">
    <ele>0.0</ele>
    <name>Position 460</name>
  </trkpt>
</root>

を使った解決法ですXML::LibXML

use strict;
use warnings;

use XML::LibXML;

my $doc = XML::LibXML->load_xml(location => 'trkpt.xml');

for my $trkpt ($doc->findnodes('/*/trkpt')) {
  unless ($trkpt->exists('time')) {
    my ($ele) = $trkpt->findnodes('ele');
    my $time = $doc->createElement('time');
    $time->appendTextNode('0.0');
    $trkpt->insertAfter($time, $ele);
  }
}

print $doc->toString(1);

そして、これは同等の使用法ですXML::Twig

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new(
  twig_roots => { trkpt => \&trkpt },
  twig_print_outside_roots => 1,
  pretty_print => 'indented'
);
$twig->parsefile('trkpt.xml');

sub trkpt {
  my ($twig, $trkpt) = @_;
  unless ($trkpt->has_child('time')) {
    my $time = XML::Twig::Elt->new(time => '0.0');
    my $ele = $trkpt->first_child('ele');
    $time->paste('after', $ele);
  }
  $twig->flush;
}
于 2013-06-15T08:05:19.937 に答える
5
  • XML パーサーを使用します。XML::LibXMLここでうまくいきます。
  • <trkpt>すべてのノードをループします。

    for my $node ( $xml->findnodes( '//trkpt') ) { ... }
    
  • ノードが存在するかどうかを検出するにはexists(またはfindnodesの古いバージョンの場合) を使用します。XML::LibXML<time>

    if $node->exists( './time' ) { ... }
    
于 2013-06-15T04:48:47.797 に答える