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::LibXML将整个 XML 文档读入内存,或者XML::Twig允许您将 XML 作为流处理并最小化使用的内存。

出于测试目的,我<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 回答