简体   繁体   English

Perl XML :: LibXML替换文本

[英]Perl XML::LibXML replace text

Simple xml file cr.xml 简单的xml文件cr.xml

<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>Bob</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>Charlie</name>
            <profession>Gardener</profession>
        </reviewer>
    </results>
</book_reviewers>

I want to loop through each reviewer and replace the name with a new one 我想遍历每位审阅者,并用一个新的名字代替这个名字。

I am not trying to use both these methods, but going by other posts in the form both of these should work but I keep getting errors: 我并没有尝试使用这两种方法,但是以其他两种形式都可以使用其他帖子,但是我一直在出错:

Can't locate object method "setData"

Can't locate object method "removeChildNodes

Can't locate object method "appendText"

#!/usr/bin/perl -w

use strict;
use XML::LibXML;

my $critics_file = "cr.xml";
my $parser = new XML::LibXML;   


print "Couldn't retrieve review details\n" 
    unless my $book_reviews  = $parser->parse_file($reviews_file);


foreach my $critics ($critic_details->findnodes('/book_reviewers/results/reviewer')) {

    my $value = $critics->findvalue('name');    #returns the correct name
    $value->removeChildNodes();
    $value->appendText('new_name');

     ##ONLY EITHER THE ABOVE METHOD OR THE ONE BELOW - NOT BOTH

    my $node  = $critics->findnodes('.//name.text()');#returns the correct name
    $node->setData('new_name');


}

Can anyone see where I am going wrong? 谁能看到我要去哪里错了?

Cheers 干杯

The problem is that this call 问题是这个电话

my $value = $critics->findvalue('name')

returns the string content of the name element, and you are trying to treat it as an XML::LibXML::Element object. 返回name元素的字符串内容,并且您试图将其视为XML::LibXML::Element对象。

Just change the method call to 只需将方法调用更改为

my ($value) = $critics->findnodes('name')

and all should be well. 一切都会好起来的。

Here is a working version of your program. 这是您程序的有效版本。

#!/usr/bin/perl

use strict;
use warnings;

use XML::LibXML;

my $reviews_file = 'cr.xml';
my $parser = XML::LibXML->new;

my $doc = $parser->parse_file($reviews_file) or die "Couldn't parse book reviewers\n";

for my $reviewer ($doc->findnodes('/book_reviewers/results/reviewer')) {
  my ($name) = $reviewer->findnodes('name');
  $name->removeChildNodes;
  $name->appendText('new_name');  
}

print $doc->toString;

output 输出

<?xml version="1.0"?>
<book_reviewers>
    <results>
        <reviewer>
            <name>new_name</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>new_name</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>new_name</name>
            <profession>Gardener</profession>
        </reviewer>
    </results>
</book_reviewers>

Solution using XML::LibXML 使用XML::LibXML解决方案

The following directly accesses the Text Node to simply and easily change the enclosed text: 以下内容直接访问“ 文本节点”,以轻松简单地更改包含的文本:

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

use XML::LibXML;

my $doc = XML::LibXML->load_xml( IO => \*DATA );

for my $text ( $doc->findnodes('//reviewer/name/text()') ) {
    $text->setData('new_name');
}

print $doc->toString;

__DATA__
<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>Bob</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>Charlie</name>
            <profession>Gardener</profession>
        </reviewer>
    </results>
</book_reviewers>

Solution using XML::Twig 使用XML::Twig解决方案

Takes the name of each reviewer and just reverses them: 取每个评论者的名字,然后颠倒他们:

use strict;
use warnings;

use XML::Twig;

my $t= XML::Twig->new( 
    twig_handlers => {
        q{//reviewer/name} => sub { $_->set_text(scalar reverse $_->text()) },
    },
    pretty_print => 'indented',
);
$t->parse( do { local $/; <DATA> } );
$t->print;

__DATA__
<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>Bob</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>Charlie</name>
            <profession>Gardener</profession>
        </reviewer>
    </results>
</book_reviewers>

Outputs: 输出:

<book_reviewers>
  <results>
    <reviewer>
      <name>ennA</name>
      <profession>Catfish wrangler</profession>
    </reviewer>
    <reviewer>
      <name>boB</name>
      <profession>Beer taster</profession>
    </reviewer>
    <reviewer>
      <name>eilrahC</name>
      <profession>Gardener</profession>
    </reviewer>
  </results>
</book_reviewers>
my $value = $critics->findvalue('name');    #returns the correct name
$value->removeChildNodes();
$value->appendText('new_name');

$value is a simple scalar that holds the text of the found xml-element <name>…</name> . $value是一个简单的标量,其中包含找到的xml-element <name>…</name>的文本。 You can not call any of those methods on a 'string', can you? 您不能在“字符串”上调用任何这些方法,可以吗?

Trying to get you into TIMTOWTDI, here is another example with more compact code: 试图使您进入TIMTOWTDI,这是另一个具有更紧凑代码的示例:

You can find all the <name>…</name> elements directly, and you can iterate over them immediately, using the 'default' variable $_ . 您可以直接找到所有<name>…</name>元素,并可以使用'default'变量$_立即对其进行迭代。

use strict;
use warnings;

use utf8;

use XML::LibXML;

my $filename = "cr.xml";

my $parser = XML::LibXML->new();
my $critic_details = $parser->parse_file("$filename") or die;

my $new_name = "new_name";

# find ALL the <book_reviewers><results><reviewers><name> nodes
foreach ($critic_details
  ->findnodes("book_reviewers/results/reviewer/name")
) {
  $_->removeChildNodes();
  $_->appendText($new_name);
}

use XML::LibXML::PrettyPrint;
my $pretty = XML::LibXML::PrettyPrint->new(
  indent_string =>' ' x4,
  element       => {
    compact       => [qw| name profession |],
    }
  );
$pretty->pretty_print($critic_details);

print $critic_details->toString;

__END__

enjoy! 请享用!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM