Search code examples
xmlperlxml-libxml

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


Solution

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