Perl:使用XML :: Twig插入XML :: Twig节点 [英] Perl: Inserting an XML::Twig node with XML::Twig

查看:244
本文介绍了Perl:使用XML :: Twig插入XML :: Twig节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在比较两个XML文件.如果我发现其中一个文件中缺少节点,则要将其插入另一个文件中.这是我一直在尝试的方法:

I am comparing two XML files. If I find a node missing in one of the files I want to insert it into the other file. Here is how I have been trying it:

my $out_file = 'fbCI_report.xml';
open my $fh_out, '>>', $out_file or die "Can't open $out_file for writing: $!";

my $currentReport = XML::Twig->new( pretty_print => 'indented' );
$currentReport->parsefile($path_to_currentReport);
print "Loaded current report.\n";

my $newReport = XML::Twig->new( pretty_print => 'indented' );
$newReport->parsefile($path_to_newReport);
print "Loaded new report.\n";

my $currentRoot   = $currentReport->root;             # get the root
my $currentBuilds = $currentRoot->first_child();      # get the builds node
my $currentXCR    = $currentBuilds->first_child();    # get the xcr node

my $newRoot   = $newReport->root;                     # get the root
my $newBuilds = $newRoot->first_child();              # get the builds node
my $newXCR    = $newBuilds->first_child();            # get the xcr node

my @currentXCRarray = $currentBuilds->children('xcr');
my @newXCRarray     = $newBuilds->children('xcr');
my $numberOfxcr     = $newBuilds->children_count();

foreach my $currentXCRmod ( @currentXCRarray ) {

    my $currentID = $currentXCRmod->att("id");

    foreach my $newXCRmod (@newXCRarray) {

        my $newID = $newXCRmod->att("id");

        if ( $newID == $currentID ) {
            last;
        }
        elsif ( $count == $numberOfxcr && $newID != $currentID ) {
            my $insert = $currentBuilds->insert_new_elt($newXCRmod);
            print "XCR does not exist in current report, adding it..\n";
        }

        $count++;
    }
}

print $fh_out $currentReport->sprint();
close $fh_out;

但是,这不会插入带有相应子节点的节点,但是我想是对该节点的引用:<XML::Twig::Elt=HASH(0x326efe0)/>.有没有办法正确插入节点?我尚未在CPAN网站上找到任何内容.

However this does not insert the node with the corresponding children but what I guess is the reference to the node: <XML::Twig::Elt=HASH(0x326efe0)/>. Is there a way to insert the node properly? I have yet to find anything on the CPAN site.

样本数据,current.xml:

Sample data, current.xml:

<project>
  <builds>
    <xcr id="13367" buildable="false">
        <artifact name="rb"/>
        <artifact name="syca"/>
    </xcr>
    <xcr id="13826" buildable="false">
        <artifact name="dcs"/>
    </xcr>
  <\builds>
<\project>

new.xml:

<project>
<builds>
    <xcr id="13367" buildable="false">
        <artifact name="rb"/>
        <artifact name="syca"/>
    </xcr>
    <xcr id="13826" buildable="false">
        <artifact name="dcs"/>
    </xcr>
    <xcr id="10867" buildable="true">
        <artifact name="smth"/>
        <artifact name="top"/>
        <artifact name="tree"/>
    </xcr>
<\builds>
<\project>

推荐答案

您是对的-这是XML::Twig::Elt的字符串化文本.

You're right - that's the stringified text of an XML::Twig::Elt.

问题是-insert_new_elt 创建一个新元素.因此,您正在做的是有效的操作,打印"元素id(XML::Twig::Elt=HASH(0x326efe0))并创建一个名为that的新节点.

The problem is - insert_new_elt creates a new element. So what you're doing is effectively, "printing" the element id ( XML::Twig::Elt=HASH(0x326efe0)) and creating a new node called that.

但是您不想这样做-您想复制一个现有的.

But you don't want to do that - you're wanting to copy an existing one.

所以我建议您要做的是:

So I would suggest what you want to do is:

my $copied_elt = $currentXCRmod -> copy;
$copied_elt -> paste ( last_child => $currentBuilds );

将哪个元素转移到("last_child"位置).

Which will transfer the element (into the 'last_child' position).

尽管我建议您的循环也许也可以改进-我建议您查看一个twig_handler,以在解析时检查文件中存在哪个ID:

Although I'd suggest that your loop is perhaps something you could improve on too - I would suggest you look at a twig_handler, to check which ID's exist in the file at parse:

my %seen_id; 
sub collect_ids {
   my ( $twig, $element ) = @_;
   $seen_id { $element->att('id') } ++; 
} 

然后在解析时调用它:

my $currentReport = XML::Twig->new(twig_handlers => { 'xcr' => \&collect_ids}, 
                                   pretty_print=>'indented');
$currentReport->parsefile($path_to_currentReport);

这将使您轻松比较/复制哪些不存在或不存在.

And this will let you easily compare/copy which ones do or don't exist.

或者(根据到目前为止的XML示例):

Or alternatively (based on your XML sample so far):

#!/usr/bin/env perl

use strict;
use warnings 'all';

use Data::Dumper;
use XML::Twig;

my $current = XML::Twig -> new ( ) -> parsefile ('test1.xml');
my $new = XML::Twig -> new (  ) -> parsefile ( 'test2.xml'); 

my $cur_builds = $current -> root -> get_xpath('./builds',0);

foreach my $xcr ( $new -> findnodes('//xcr') ) {
   my $id = $xcr -> att('id'); 
   if ( not $current -> findnodes("//xcr[\@id=\"$id\"]") ) {
      print "$id not in current, copying\n"; 
      my $copy = $xcr -> copy; 
      $copy -> paste ( last_child => $cur_builds ); 
   }
}

$current -> set_pretty_print('indented_a');
$current -> print;

这篇关于Perl:使用XML :: Twig插入XML :: Twig节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆