如何将XML元素A添加到没有A作为子元素的元素B.

mom*_*aaa 2 perl xml-parsing

我正在处理类似于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>
Run Code Online (Sandbox Code Playgroud)

如您所见,某些<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();
}
Run Code Online (Sandbox Code Playgroud)

无法在未定义的值上调用方法"textContent"...

我怎样才能让它变得更聪明?也就是说,如果遇到未定义的$time,它会将其写入<time>gpx文件,并且不会发生错误.

Bor*_*din 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>
Run Code Online (Sandbox Code Playgroud)

这是一个使用的解决方案 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);
Run Code Online (Sandbox Code Playgroud)

这是一个等价的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;
}
Run Code Online (Sandbox Code Playgroud)


Zai*_*aid 5