我正在处理类似于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>
添加到那些不包含它的<time>
元素中?
在读取文件时,如果XML节点不包含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();
}
,则会产生错误:
$time
无法在...
的未定义值上调用方法“textContent”
如何让它变得更聪明?也就是说,如果它遇到未定义的<time>
,它会将{{1}}写入gpx文件,并且不会发生错误。
答案 0 :(得分: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);
这里等同于usiong 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;
}
答案 1 :(得分:5)
XML::LibXML
在这里会很好。遍历所有<trkpt>
个节点:
for my $node ( $xml->findnodes( '//trkpt') ) { ... }
使用exists
(findnodes
用于旧版XML::LibXML
)来检测<time>
节点是否存在:
if $node->exists( './time' ) { ... }