1

I would like to add/delete value into xml file using XML::Simple. my following code doesn't work for adding/deleting into xml file. please help to suggest how should i add/delete specific value into XML file using XML::Simple. thanks alot for your help :)

  use XML::Simple;
  use Data::Dumper;
  use feature 'say';
  my $data;
foreach my $run (@{XMLin(\*DATA)->{Run}}) {
    $data->{$run->{NAME}}->{$run->{tag}} =
      {map { $_ => 1 } @{$run->{List}->{Fruit}}};
}
my @user_input = qw(
  Basket1:2A:apple:orange:peach:
  Basket2:2B:apple:banana:orange:grapes:
);
foreach my $line (@user_input) {
    chomp $line
      ; # we don't need this in my example, but you do when you read from a file
    my ($name, $Tag, @fruitlist) = split /:/, $line;
    foreach my $fruit_list (@fruitlist) {
        if (exists $data->{$name}->{$Tag}->{$fruit_list}) {
            say "$fruit_list - existing\n";
          delete $data ->{Start}[0]{Run}[0]{List}[0]{Fruit}{$fruit_list};
          say "$fruit_list deleted\n";
          print XMLout($data);
        }
        else {
            say "$fruit_list - no existing\n";
           $data->{Start}->[0]->{Run}->[0]->{List}->[0]->{Fruit}->[2] = $fruit_list;
           say "$fruit_list added\n";
           print XMLout($data);
        }
    }
}
__DATA__
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Start>
        <Run>
                <NAME>Basket1</NAME>
                <tag>2A</tag>
                <List>
                        <Fruit>pineapple</Fruit>
                        <Fruit>grapes</Fruit>
                </List>
        </Run>
        <Run>
                <NAME>Basket2</NAME>
                <tag>2B</tag>
                <List>
                        <Fruit>Apple</Fruit>
                        <Fruit>dragonfruit</Fruit>
                </List>
        </Run>
          <Run>
                <NAME>Basket3</NAME>
                <tag>2C</tag>
                <List>
                        <Fruit>grapes</Fruit>
                        <Fruit>banana</Fruit>
                </List>
        </Run>
</Start>
Flora
  • 55
  • 4
  • 3
    Stay away from [XML::Simple](http://p3rl.org/XML::Simple) - read "STATUS OF THIS MODULE" in its documentation or [Why is XML::Simple Discouraged?](https://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged) here on SO. – choroba May 25 '20 at 16:48
  • i tried to use XML::LibXML. but seems need to install . i m using perl on window which is active perl and i cannot install the package. getting time out and hang. not sure whether it is network permission issue or not :( – Flora May 25 '20 at 17:56
  • *"getting time out and hang"* It may take several minutes to install the module, try install it with verbose option `cpanm -v XML::LibXML` to see if it makes progress or hangs – Håkon Hægland May 25 '20 at 18:51
  • 'cpanm' is not recognized as an internal or external command, operable program or batch file. it is showing like that when i tried to install it from command prompt :( – Flora May 25 '20 at 19:13
  • If you are ever going to work with any XML (probably "yes") then it's worth solving installation issues so to have a good module (or two) for it. I use `XML::LibXML`, which is great, and `XML::Twig` is also a great full dedicated XML processing library. And then `Mojo::DOM` does both HTML and XML – zdim May 25 '20 at 20:44
  • @Flora *"'cpanm' is not recognized as an internal or external command"* : Yes you are right, I was not able to install cpanm with ActivePerl either. I would recommend that you try [Strawberry Perl](http://strawberryperl.com/) instead. – Håkon Hægland May 25 '20 at 22:28
  • `ppm install XML::LibXML` might work with ActivePerl? `cpan XML::LibXML` should, but ActiveState dropped for a while, and I don't know what state it's in now. In any case, the solution isn't using a severely broken module; it's getting help installing a module that's not severely broken – ikegami May 26 '20 at 01:16

1 Answers1

2

XMLin reads in an xml XMLout generates an xml. You need to write the output of XMLout for the file to change.

This code should work:

    use XML::Simple;
use Data::Dumper;
use feature 'say';
use autodie;

my $data = XMLin('./test.xml');

my @user_input = qw(
  Basket1:2A:apple:orange:peach:
  Basket2:2B:apple:banana:orange:grapes:
);

my $new;
foreach my $line (@user_input) {
    chomp $line;
    # we don't need this in my example, but you do when you read from a file
    my ($name, $Tag, @fruitlist) = split /:/, $line;

      foreach my $fruit ( @{$data->{Run}} ) {
        my $list = {};
        %{$list} = map { $_ => 1 } @{ $fruit->{List}->{Fruit} };

        if ( $fruit->{NAME} eq $name && $fruit->{tag} eq $Tag ) {

          my @test = @{ $fruit->{List}->{Fruit} };
          foreach $f ( @fruitlist ) {
            if ( !$list->{$f} ) {
              push @test, $f;
            }
          }
          print "$fruit->{NAME} $fruit->{tag}";
          print Dumper(\@test);
          $fruit->{List}->{Fruit} = \@test;

        }
      }

}
open (my $fh, '>', 'new.xml' );
print $fh XMLout( $data, RootName => "Start" );
close $fh;
Dragos Trif
  • 276
  • 1
  • 12
  • thanks alot :) it's really work well. may i know if i want to remove specific value for example text.xml basket 2 has apple which is same as user's input basket2 value, which function should i use to remove specific value? should i use delete $fruit->{List}[0]{Fruit}[\@test] ? – Flora May 25 '20 at 23:00
  • That will die if any of the lists contains only one element. Or none. – ikegami May 26 '20 at 01:18
  • @ikegami in this code, for adding the value is used as push $test,$f;$fruit->{list}->{Fruit}=\@test; for deleting the specific value , which function should i use to delete specific value from xml file? – Flora May 26 '20 at 06:06
  • @Flora maybe this post will help: https://stackoverflow.com/questions/11021693/comparing-two-arrays-removing-items-that-match – Dragos Trif May 26 '20 at 17:56