Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add new nodes/elements to XML::LibXML object

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

like image 730
Keryn Drake Avatar asked Feb 13 '23 23:02

Keryn Drake


2 Answers

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>
like image 87
KeepCalmAndCarryOn Avatar answered Feb 27 '23 00:02

KeepCalmAndCarryOn


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!

like image 22
vanHoesel Avatar answered Feb 27 '23 02:02

vanHoesel