Data.xml
<people>
<person name="John">
<param name="age" value="21" />
</person>
<person name="Jane">
<param name="age" value="25" />
</person>
</people>
I have this piece of XML. I'm working on a script to append <person>
nodes to the <people>
node. I'm using XML::Simple
(Please refrain from suggesting that i use another library, i'm aware of its difficulties).
my $remove_person = "Jane";
my $xml = XMLin('data.xml', ForceArray => 1, KeepRoot => 1, KeyAttr => []);
if(exists $xml->{people}[0]{person}){
my $var = $xml->{people}[0]{person};
my $count = @$var;
my $person_index = 0;
for(my $i = 0; $i < $count; $i++){
if($xml->{people}[0]{person}[$i]->{name} eq $remove_person){
print "Person found at " . $person_index . " index";
$person_index = $i;
$person_to_remove = $xml->{people}[0]{person}[$i];
}
}
} else {
print "Person not found in data.xml\r";
}
The above piece of code will give me the index of the node i wish to remove.
Its from this point that i'm having my trouble. I cannot figure a correct way to remove this index from the data.
So far i've tried a method of using splice
, which returned the section of XML i want to remove, then i used XMLout()
to convert the array back to XML. Using =~ s///g
, i was able to edit node changes (<person>
became <opt>
). Once i'd XMLout()'ed
the original data.xml structure, i attempted to string replace the variable of the removable section of XML, with empty string of the original structure.
Obviously, this didn't work.
my $new_xml = XMLout($xml, KeepRoot => 1);
my $remove_xml = XMLout($person_to_remove, KeepRoot => 1);
$remove_xml =~ s/opt/person/g;
$new_xml =~ s/($remove_xml)//g; # facepalm, i know
How would i remove this section of XML, either by array data removal, or plain file text removal so as to write back to the original data.xml file the new structure?
As you have been already told, the point of XML::Simple is to use Perl data structures instead of string manipulation. So, forget s///
and try
my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1);
my $remove = 'Jane';
delete $xml->{people}[0]{person}{$remove};
print XMLout($xml, KeepRoot => 1);
or, with empty KeyAttr
my $xml = XMLin($data, ForceArray => 1, KeepRoot => 1, KeyAttr => []);
@{ $xml->{people}[0]{person} } = grep $_->{name} ne $remove,
@{ $xml->{people}[0]{person} };
print XMLout($xml, KeepRoot => 1);
For comparison, the same task in XML::XSH2:
open data.xml ;
my $remove = 'Jane' ;
delete /people/person[@name=$remove] ;
save :b ;