marmarta
marmarta

Reputation: 838

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

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.

Upvotes: 5

Views: 1517

Answers (2)

Borodin
Borodin

Reputation: 126722

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.

Upvotes: 3

ikegami
ikegami

Reputation: 385655

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, ());

Upvotes: 2

Related Questions