xmlperlxml-parsingxml-libxmlchild-nodes

How to use Perl LibXML to add a ChildNode where one is missing?


I am using libXML to update a batch of XML settings files. Here is an example of the section of xml I am trying to update:

<Setting SID="2091">
  <Name>HME Cloud User Email</Name>
  <Value/>
</Setting>

I can properly update that section with the following code.

#!/usr/bin/perl 

use File::Basename;
use XML::LibXML;
use XML::LibXML::XPathContext; 
 
@files = glob('C:\Users\1025144\Documents\timer_test\*.xml'); 

foreach $file (@files) 
{
    my $dom = XML::LibXML->load_xml(location => $file);
    my $xpc = XML::LibXML::XPathContext->new($dom);
    $xpc->registerNs('xsd',  'http://hme.com/Settings.xsd');
    
    #Add email 
    my($match9) = $xpc->findnodes('//xsd:Settings/xsd:Setting[@SID="2091"]/xsd:Value');
    $match9->removeChildNodes();
    $match9->appendText('email@email.com');
    
    open (OUTFILE, ">$file");               
    print OUTFILE $dom;
}

print "XML Files Updated."

but the issue is some of the settings files are missing the Value node for this SID, see example below:

<Setting SID="2091">
  <Name>HME Cloud User Email</Name>
</Setting>

I have been looking at the addChild to attempt to place the node into this SID but I cant seem to figure out the syntax. I use perl off and on so I am hoping someone can help me figure out how to add this node or if there is an alternative solution that I can use if the SID has the Value node or not.

Any help is appreciated - Thanks!


Solution

  • Use an if, if the Value doesn't exist, create it using addNewChild.

    #! /usr/bin/perl
    use warnings;
    use strict;
    use feature qw{ say };
    
    use XML::LibXML;
    
    my @files = @ARGV;
    
    my $uri = 'http://hme.com/Settings.xsd';
    for my $file (@files) {
        my $dom = 'XML::LibXML'->load_xml(location => $file);
        my $xpc = 'XML::LibXML::XPathContext'->new($dom);
        $xpc->registerNs('xsd',  $uri);
    
        if (my ($email) = $xpc->findnodes('//xsd:Settings/xsd:Setting[@SID="2091"]/xsd:Value')) {
            $email->removeChildNodes;
            $email->appendText('email@email.com');
        } else {
            my ($setting) = $xpc->findnodes('//xsd:Settings/xsd:Setting[@SID="2091"]');
            $setting->addNewChild($uri, 'Value')->appendText('email@email.com');
        }
    
        $dom->toFile("$file.new");
    }
    
    say "XML Files Updated."
    

    Notes: