使用Perl基于其他更新xml属性值
| 这是我的示例xml文件 
  
  
  <manifest>
 <default>
    <remote>remote1</remote>
    <revision>rev1</revision>
 </default>
 <project>
    <name>common</name>
    <path>opensource/device</path>
    <revision>sa</revision>
    <x-ship>oss</x-ship>
 </project>
 <project>
   <name>external</name>
   <path>source/tp</path>
   <x-ship>none</x-ship>
 </project>
 <project>
   <name>ws</name>
   <path>opensource/ws</path>
   <remote>nj</remote>
   <revision>myno</revision>
   <x-ship>none</x-ship>
 </project>
</manifest>在此我需要仅在< path>时更新修订值.在其中有“opensource”字符串. 我搜索了很多但找不到任何有用的东西来实现这一点,我可以根据下面的位置修改值,有人可以帮我更新吗?或者让我知道是否有更好的Perl库来执行此操作. #!/usr/bin/perl
use strict;
use warnings;
use XML::Simple;
my $xml_file = 'dev.xml';
my $xml = XMLin(
    $xml_file,KeepRoot => 1,ForceArray => 1,);
$xml->{manifest}->[0]->{project}->[2]->{revision} = 'kyo';
XMLout(
    $xml,NoAttr => 1,OutputFile => $xml_file,);解决方法
 肯定存在学习曲线,但 
  XML::Twig和XPath语法可以很好地处理这个问题.以下内容演示了您提供的虚假数据的变体.请注意,twig的一个重要功能是能够随时解析数据,而不必将极大的XML文件完全加载到内存中.这可能不是您的情况下的限制,但对某些人来说这是一个重要的特征. use strict;
use warnings;
use XML::Twig;
my $data = do { local $/; <DATA> };
my $t= XML::Twig->new( 
    twig_handlers => {
        q{project[string(path) =~ /bopensourceb/]/revision} => &;revision,},pretty_print => 'indented',);
$t->parse( $data );
$t->print;
sub revision {
    my ($twig,$rev) = @_;
    $rev->set_text("open source - " . $rev->text());
}
__DATA__
<manifest>
 <default>
    <remote>remote1</remote>
    <revision>rev1</revision>
 </default>
 <project>
    <name>common</name>
    <path>NOTopensource/device</path>
    <revision>sa</revision>
    <x-ship>oss</x-ship>
 </project>
 <project>
   <name>external</name>
   <path>source/tp</path>
   <x-ship>none</x-ship>
 </project>
 <project>
   <name>ws</name>
   <path>opensource/ws</path>
   <remote>nj</remote>
   <revision>myno</revision>
   <x-ship>none</x-ship>
 </project>
</manifest>输出: 你会注意到最后一个版本有开源 – 前缀是它. <manifest>
  <default>
    <remote>remote1</remote>
    <revision>rev1</revision>
  </default>
  <project>
    <name>common</name>
    <path>NOTopensource/device</path>
    <revision>sa</revision>
    <x-ship>oss</x-ship>
  </project>
  <project>
    <name>external</name>
    <path>source/tp</path>
    <x-ship>none</x-ship>
  </project>
  <project>
    <name>ws</name>
    <path>opensource/ws</path>
    <remote>nj</remote>
    <revision>open source - myno</revision>
    <x-ship>none</x-ship>
  </project>
</manifest>关于兄弟元素的附录: 是的,有一些方法可以在一个树枝内遍历到附近的xml元素.例如,如果我想提取我正在编辑的修订版的名称,并将其放在新文本中,我可以执行以下操作: sub revision {
    my ($twig,$rev) = @_;
    my $name = $rev->parent()->first_child("name");
    $rev->set_text("open source - " $name->text() . ' - '. $rev->text());
}请注意,ws现已添加到已编辑的修订版标记中: <project>
    <name>ws</name>
    <path>opensource/ws</path>
    <remote>nj</remote>
    <revision>open source - ws - myno</revision>
    <x-ship>none</x-ship>
  </project>这种将树枝遍历到附近元素的方法通常是一种有用的过滤方法.我很容易做到这一点来强制执行这个分支是一个包含opensource的路径,但是如果熟悉xpath语法,那么在xpath中为处理程序设置该需求是很方便的. 还要注意,在上面的例子中,我假设有一个类型名称的兄弟.通常我会在调用之前检查以确保 – > gt; text()或者可能会出错. 关于属性的附录: 关于您的边缘情况与替代格式: <project path="opensource" revision="apple" name="platform" x-ship="none"/> 上面包含与其他项目相同的数据,但它们不是值为子元素,而是属性.这也是XML的一个特性,但它是不同的,因此必须以不同的方式处理. 以下是对最初建议的脚本的编辑,该脚本为包含路径属性与子项的项目添加新的处理程序: use strict;
use warnings;
use XML::Twig;
my $data = do { local $/; <DATA> };
my $t= XML::Twig->new( 
    twig_handlers => {
        q{project[string(path) =~ /bopensourceb/]/revision} => &;revision,q{project[@path =~ /bopensourceb/]} => &;project,$rev) = @_;
    $rev->set_text("open source - " . $rev->text());
}
sub project {
    my ($twig,$project) = @_;
    $project->set_att(
        revision => 'open source - ' . $project->{att}{revision},);
}
__DATA__
<manifest>
 <default>
    <remote>remote1</remote>
    <revision>rev1</revision>
 </default>
 <project>
    <name>common</name>
    <path>NOTopensource/device</path>
    <revision>sa</revision>
    <x-ship>oss</x-ship>
 </project>
 <project path="opensource" revision="apple" name="platform" x-ship="none"/>
 <project>
   <name>external</name>
   <path>source/tp</path>
   <x-ship>none</x-ship>
 </project>
 <project>
   <name>ws</name>
   <path>opensource/ws</path>
   <remote>nj</remote>
   <revision>myno</revision>
   <x-ship>none</x-ship>
 </project>
</manifest>只是为了给你一些比较和学习的东西,这里是相同的代码,但在处理程序中使用过滤而不是使用xpath: twig_handlers => {
        q{project[string(path) =~ /bopensourceb/]/revision} => &;revision,q{project} => &;project,...
sub project {
    my ($twig,$project) = @_;
    if ($project->{att}{path} && $project->{att}{path} =~ /bopensourceb/) {
        $project->set_att(
            revision => 'open source - ' . $project->{att}{revision},);
    }
}(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! | 
