Вот базовый пример 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>

И я хочу добавить это:

<reviewer>
    <name>Joan</name>
    <profession>Jett</profession>
 </reviewer>

Я пробовал комбинации многих решений, вот одно, которое, по крайней мере, не вызывает ошибки, но оно также не работает.

#!/usr/bin/perl
use XML::LibXML;
use strict;

my $filename = "cr.xml";

my $parser = XML::LibXML->new();
my $critic_details = $parser->parse_file("$filename") or die;
my $new_reviewer = $critic_details->documentElement;
my $reviewer_name = $critic_details->documentElement;
my $reviewer_prof = $critic_details->documentElement;
my $newnode = $critic_details->documentElement;

 for my $reviewers($critic_details->findnodes("book_reviewers/results/reviewers")){
     $new_reviewer = $reviewers->createElement("reviewer");
    $reviewer_name = $new_reviewer->addChild("name");
    $reviewer_name->appendText("Joan");
    $reviewer_prof = $new_reviewer->addChild("profession");
    $reviewer_prof->appendText("Jett");
    $newnode = $reviewers->addSibling($new_reviewer); #also tried addChild

}
print $critic_details->toString;

Результат, который я получаю:

<?xml version="1.0"?>
<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>

Это просто исходные данные

Любая помощь очень ценится - я очень новичок в Perl и XML Cheers

4
Keryn Drake 18 Май 2014 в 13:29

3 ответа

Лучший ответ

Есть много способов сделать это

Таким образом, узлы создаются отдельно и складываются вместе. Он не готов к производству, поскольку предполагает наличие раздела

#!/usr/bin/perl
use XML::LibXML;
use strict;

my $filename = "cr.xml";

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

my $reviewer  = $critic_details->findnodes("book_reviewers/results")->[0];

my $node = XML::LibXML::Element->new("reviewer");

my $p = XML::LibXML::Element->new("profession");
my $pn = XML::LibXML::Text->new("Jett");
$p->addChild($pn);

my $n = XML::LibXML::Element->new("name");
my $nn = XML::LibXML::Text->new("Joan");
$n->addChild($nn);

$node->addChild($p);
$node->addChild($n);

$reviewer->addChild($node);

print $critic_details->toString;

Что дает это

<?xml version="1.0"?>
<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>
    <reviewer><profession>Jett</profession><name>Joan</name></reviewer></results>
</book_reviewers>
4
KeepCalmAndCarryOn 18 Май 2014 в 10:57

Чтобы помочь вам с некоторыми изящными вещами XML::LibXML и помочь вам понять, как работает XML, я разместил здесь еще один ответ. Может быть, вы тоже найдете в нем полезные подсказки:

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;

# find ALL the <book_reviewers><results> nodes
my @results = $critic_details->findnodes("book_reviewers/results");
die "no result node in xml-file" unless @results;

my ($name, $profession) = ("Joan", "Jett");

#
# Here gets the work done, put this in a loop for more entries
#

# add a new <reviewer> node to the LAST <results>
my $reviewer_node_child;
my $reviewer_node = $results[-1]->addNewChild(undef, "reviewer");

# create a child node
$reviewer_node_child =  $reviewer_node->addNewChild(undef, "name");
$reviewer_node_child->appendTextNode($name);

# create a child node
$reviewer_node_child =  $reviewer_node->addNewChild(undef, "profession");
$reviewer_node_child->appendTextNode($profession);

#
# Done the heavy power lifting
#

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__

Здесь необходимы undef в методах addNewChild. Они используются для установки XML-NameSpace, которое вам здесь не понадобится, но в огромных XML-документах это действительно правильный путь.

Кроме того, я добавил XML::LibXML::PrettyPrint, чтобы показать вам, как вернуться к красивому синтаксису. Простите за добавление use… в конце скрипта.

Что дает следующий результат:

<?xml version="1.0"?>
<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>
        <reviewer>
            <name>Joan</name>
            <profession>Jett</profession>
        </reviewer>
    </results>
</book_reviewers>

Наслаждайтесь XML и Perl, очень мощным, но устрашающим сочетанием инструментов!

3
vanHoesel 18 Май 2014 в 15:36

Можно использовать XML::LibXML для импорта узлов из одного XML-документа в Другой. Это полезно, поскольку вам не придется создавать новые данные явно с использованием объектов, а вместо этого можно просто использовать стандартную нотацию XML.

Ниже показано это. Это можно легко расширить до более чем одного нового рецензента, установив корневой узел в новом документе и затем перебирая найденные узлы вместо того, чтобы просто выбирать первый.

#!/usr/bin/perl

use strict;
use warnings;

use XML::LibXML;

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

my $newnode = XML::LibXML->load_xml(string => <<'END_STRING')->findnodes('//*')->[0];
<reviewer>
    <name>Joan</name>
    <profession>Jett</profession>
</reviewer>
END_STRING

$dom->findnodes("book_reviewers/results")->[0]->addChild($newnode);

print $dom->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>

Выходы:

<?xml version="1.0"?>
<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>
    <reviewer>
    <name>Joan</name>
    <profession>Jett</profession>
</reviewer></results>
</book_reviewers>
1
Miller 19 Май 2014 в 03:43