0

我有一个很长的 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,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->setAttribute( $aname, $avalue ); 但这是抛出异常。请指教。

4

2 回答 2

4

你的代码太复杂了。您不需要解析器,不需要元素,只需找到 url 并更改它们:

#!/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');
于 2013-09-17T07:43:48.197 回答
1

You can try with XML::Twig module. It has the twig_handlers option that selects the tags you want and triggers a handler. The default variable $_ has the element and its method set_att() lets you change its value easily:

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

Run it like:

perl script.pl xmlfile

That yields:

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

EDIT: Mirod's version pointed out in comments of a more efficient parsing using 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 );
于 2013-09-17T07:12:06.820 回答