加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

使用Perl基于其他更新xml属性值

发布时间:2020-12-15 21:16:26 所属栏目:大数据 来源:网络整理
导读:这是我的示例xml文件 manifest default remoteremote1/remote revisionrev1/revision /default project namecommon/name pathopensource/device/path revisionsa/revision x-shiposs/x-ship /project project nameexternal/name pathsource/tp/path x-shipno
这是我的示例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},);
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读