使用perl修改xml标记的属性值

时间:2013-09-17 06:33:41

标签: perl xpath xml-parsing

我有一个非常长的xml,我希望更新其中一个非常深嵌套的标记的属性值,所以不希望逐个节点地去。对于预期节点,结构也不同,如下所示: 输入XML是:

<Re>
<Co Class="Parameter" ID="CSCP001" Status="Available">
<FileSpec URL="c://mine/testfiles/wln/c.txt"/>
<CoOp Operation="Tag" SourceCS="RGB" SourceObjects="All">
<FileSpec Resource="SourceProfile" URL="c://mine/testfiles/wln/d.txt"/>
</CoOp>
</Co>
<Ru Class="Parameter" ID="IDR002" PartIDKeys="Run" Status="Available">
<Ru EndOfDocument="true" Pages="0" Run="1" RunTag="First">
<La>
<FileSpec URL="c://mine/testfiles/wln/e.txt"/>
</La>
</Ru>
</Ru>
</Re>

我希望输出xml为

<Re>
<Co Class="Parameter" ID="CSCP001" Status="Available">
<FileSpec URL="d://yours/wln/c.txt"/>
<CoOp Operation="Tag" SourceCS="RGB" SourceObjects="All">
<FileSpec Resource="SourceProfile" URL="d://yours/wln/d.txt"/>
</CoOp>
</Co>
<Ru Class="Parameter" ID="IDR002" PartIDKeys="Run" Status="Available">
<Ru EndOfDocument="true" Pages="0" Run="1" RunTag="First">
<La>
<FileSpec URL="d://yours/wln/e.txt"/>
</La>
</Ru>
</Ru>
</Re>

我尝试使用xml simple,xmllib但无法执行所需的操作。我是perl编程的新手。

use XML::LibXML qw( );
use XML::LibXML;
use Data::Dumper;  

my $xml = "a.txt";
my $xpath_expression = 'FileSpec';

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file($xml) or warn "Could not";

my $parser1 = XML::LibXML::Element->new($xml);


for my $FileSpec1 ($doc->getElementsByTagName('FileSpec')) 
{
print $FileSpec1;
my $xpath = '$FileSpec1/@URL';
my ($attr) = $doc->findnodes($xpath);    
$attr->setValue('dfdsa'); 
my ($URL1) = $FileSpec1->findvalue('@URL');
print $URL1;
}

我尝试使用$ node-&gt; setAttribute($ aname,$ avalue);但这是抛出异常。请指教。

2 个答案:

答案 0 :(得分:4)

您的代码太复杂了。你不需要解析器,没有元素,只需找到网址并进行更改:

#!/usr/bin/perl
use warnings;
use strict;

use XML::LibXML;

my $xml = 'XML::LibXML'->load_xml(location => 'a.xml') ;

for my $url ($xml->findnodes('//FileSpec/@URL')) {
    my $value = $url->getValue;
    $value =~ s{c://mine/testfiles}{d://yours};
    $url->setValue($value);
}

$xml->toFile('new.xml');

答案 1 :(得分:1)

您可以尝试使用XML::Twig模块。它具有twig_handlers选项,用于选择所需的标记并触发处理程序。默认变量$_包含元素,其方法set_att()可让您轻松更改其值:

#!/usr/bin/env perl

use warnings;
use strict;
use XML::Twig;

my $new_url = q{d://yours/wln/d.txt};

my $twig = XML::Twig->new(
        twig_handlers => {
                'FileSpec' => sub { $_->set_att( 'URL', $new_url ) }
         },
        pretty_print => 'indented',
)->parsefile( shift )->print();

像以下一样运行:

perl script.pl xmlfile

产量:

<Re>
  <Co Class="Parameter" ID="CSCP001" Status="Available">
    <FileSpec URL="d://yours/wln/d.txt"/>
    <CoOp Operation="Tag" SourceCS="RGB" SourceObjects="All">
      <FileSpec Resource="SourceProfile" URL="d://yours/wln/d.txt"/>
    </CoOp>
  </Co>
  <Ru Class="Parameter" ID="IDR002" PartIDKeys="Run" Status="Available">
    <Ru EndOfDocument="true" Pages="0" Run="1" RunTag="First">
      <La>
        <FileSpec URL="d://yours/wln/d.txt"/>
      </La>
    </Ru>
  </Ru>
</Re>

编辑Mirod's版本在使用twig_roots()进行更有效解析的评论中指出:

#!/usr/bin/env perl

use warnings;
use strict;
use XML::Twig;

my $new_url = q{d://yours/wln/d.txt};

my $twig = XML::Twig->new(
        twig_roots => {
                'FileSpec' => sub { $_->set_att( 'URL', $new_url ); $_->flush }
        },
        twig_print_outside_roots => 1,
        pretty_print => 'indented',
)->parsefile( shift );