Here is a basic XML document example
<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>
And I want to add this:
<reviewer>
<name>Joan</name>
<profession>Jett</profession>
</reviewer>
I have tried a combinations of many solutions, here is one that, at least, doesn't throw an error, but, it also doesn't work.
#!/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;
The output that i get is:
<?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>
Which is just the original data
Any help greatly appreciated - I am very new to both Perl and XML Cheers
There are lots of ways to do this
This way creates the nodes separately and puts it together. It isn't production ready as it assumes there is a section
#!/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;
which gives this
<?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>
Just to help you out with some more neat things of XML::LibXML
and get you to a bit more easy way to understand how XML works, I posted here another answer. Maybe you wil find some useful clues in it as well:
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__
The undef
in the addNewChild
methods are needed here. They are used to set the XML-NameSpace, which you will not need here, but in huge XML-documents is really the way to go.
Also, I added XML::LibXML::PrettyPrint
just to show you how to get back to the nice pretty looking syntax. Forgive me for adding the use…
add the end of the script.
which produces the this result:
<?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>
Enjoy XML and Perl, a very powerful but daunting combination of tools!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With