Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl and XML::Smart - how to remove a node from an XML file

Tags:

xml

perl

I'm writing a simple Perl script that uses XML::Smart to create and parse an XML file. I have run into a problem with deleting XML nodes. I have the following code:

if ( exists $XML->{object}[$n] ) {
    delete $XML->{object}[$n] ;
};
$XML->save('dane.xml') ;

It does what is expected - namely, the correct node is deleted. However, when I later try to list all nodes (children of a particular root), using the code below (which usually works):

my @objects = $XML->{object}('@') ;
foreach my $object (@objects) {
    say "$object->{address}";
}; 

Perl lists all nodes up to the one before the deleted one, and then spits out the following error:

Not a HASH reference at g:/Dwimperl/perl/site/lib/XML/Smart/Tie.pm line 48, <STDIN> line 2.

I'm stumped - I tried using various permutations of $XML->data(); but none worked. I would prefer to continue using XML::Smart for this task, so I hope this problem can be solved within this particular library.

like image 452
marmarta Avatar asked Jan 07 '13 01:01

marmarta


2 Answers

While XML::Smart is way better than XML::Simple, on which it is based, in my opinion it is still really not very good at representing XML data. In this case you have to be aware that the node you want to delete is an element of a Perl array, and using delete on it will simply set the element to undef while leaving it in place (unless it happens to be the last element of the array).

To manipulate arrays like this you need splice, which correctly removes elements and moves later ones down to fill the space. Use

splice @{ $XML->{object} }, $n, 1

instead of your delete and your code should work for you.

like image 54
Borodin Avatar answered Nov 10 '22 19:11

Borodin


Never use exists and delete on an array element. Neither do anything useful.

To remove an element from an array, you need to shift down all the other elements. splice can do this.

splice(@{ $XML->{object} }, $n, 1);

Or if it helps you understand better,

splice(@{ $XML->{object} }, $n, 1, ());
like image 41
ikegami Avatar answered Nov 10 '22 21:11

ikegami