【问题标题】:Perl: Inserting an XML::Twig node with XML::TwigPerl:使用 XML::Twig 插入 XML::Twig 节点
【发布时间】:2016-07-21 21:58:29
【问题描述】:

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

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 网站上找到任何东西。

样本数据,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>

新的.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 在这里会有所帮助!
  • 我还建议不要只使用first_child 来遍历你的树,而是使用xpath 明确地这样做。
  • 那么对于这些​​ XML 示例,您是否希望基于 xcr id 进行合并?
  • @Sobrique 是的,这正是我想在这里做的。我想知道为什么我从来没有想到这个词。

标签: perl xml-twig


【解决方案1】:

您可能应该移动节点(我不记得当您尝试插入已经是树的一部分的元素时会发生什么)。所以写$newXCRmo-&gt;move( first_child( $currentBuilds)) 看看这是否能改善情况。

我没有太多时间看你的代码,所以可能还有其他问题。

【讨论】:

  • 消息是“无法粘贴属于树的元素”
【解决方案2】:

你是对的 - 那是 XML::Twig::Elt 的字符串化文本。

问题是 - insert_new_elt 创建一个新元素。所以你正在做的是有效地“打印”元素 id (XML::Twig::Elt=HASH(0x326efe0)) 并创建一个名为它的新节点。

但您不想这样做 - 您想要复制现有的。

所以我建议你想做的是:

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

这将转移元素(到“last_child”位置)。

虽然我建议您的循环可能也是您可以改进的地方 - 我建议您查看 twig_handler,以检查解析时文件中存在的 ID:

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);

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

或者(基于您目前的 XML 示例):

#!/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;

【讨论】:

    【解决方案3】:

    你的比较循环“由内而外”

    此外,测试$count == $numberOfxcr 永远不会成功,因为循环foreach my $newXCRmod (@newXCRarray) 将在此之前终止

    这是您的代码的改进版本,它使用 XPath 表达式以及来自 List::Utilany 使循环更简洁

    use strict;
    use warnings 'all';
    
    use XML::Twig;
    use List::Util 'any';
    
    my ( $path_to_curr_report, $path_to_new_report ) = qw/ current.xml  new.xml /;
    my $out_file = 'fbCI_report.xml';
    
    
    my $curr_report = XML::Twig->new->parsefile($path_to_curr_report);
    my $new_report  = XML::Twig->new->parsefile($path_to_new_report);
    
    my ($curr_builds) = $curr_report->findnodes('/project/builds');
    
    for my $new_xcr_mod ( $new_report->findnodes('/project/builds/xcr') ) {
    
        my $new_id = $new_xcr_mod->att('id');
    
        next if any { $new_id eq $_->att('id') } $curr_report->findnodes('/project/builds/xcr');
    
        print qq{XCR with ID "$new_id" does not exist in current report. Adding it.\n};
        $new_xcr_mod->copy->paste( last_child => $curr_builds );
    }
    
    {
        $curr_report->set_pretty_print('indented');
        open my $fh, '>', $out_file or die "Can't open $out_file for writing: $!";
        $curr_report->print($fh);
        close $fh;
    }
    

    输出

    XCR with ID "10867" does not exist in current report. Adding it.
    
    <project>
      <builds>
        <xcr buildable="false" id="13367">
          <artifact name="rb"/>
          <artifact name="syca"/>
        </xcr>
        <xcr buildable="false" id="13826">
          <artifact name="dcs"/>
        </xcr>
        <xcr buildable="true" id="10867">
          <artifact name="smth"/>
          <artifact name="top"/>
          <artifact name="tree"/>
        </xcr>
      </builds>
    </project>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2018-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多