Selvakumar has asked for the wisdom of the Perl Monks concerning the following question:

I am using the below code to delete an element, but i need to add xpath conditions here. i tried with the below code but it deletes all elements. it should not delete the first occurance and it should delete the second child only.
my $twig_to_del=XML::Twig->new( twig_handlers=>{ #to_delete elements '/document/header[2]'=>\&eleme +nt_delete, }, ); $twig_to_del->parse($temp); $twig_to_del->purge; sub element_delete { my ($twig, $element)= @_; $element->delete; }

Replies are listed 'Best First'.
Re: xml::twig delete element
by mirod (Canon) on Oct 13, 2009 at 05:49 UTC

    You can't do that. '/document/header[2]' should trigger an error, [2] is not supported. You will need to call the handler on all headers, and manage the state yourself to see if you have deleted the second one.

    This should work, by keeping track taht the second header has already been deleted in a hidden attribute in the parent:

    #!/usr/bin/perl use strict; use warnings; use XML::Twig; my $twig_to_del=XML::Twig->new( twig_handlers=>{ #to_delete elements '/document/header'=>\&element_ +delete, }, ) ->parse(\*DATA) ->print; sub element_delete { my ($twig, $element)= @_; my $first_header= $element->prev_sibling( 'header'); if( $first_header && ! $first_header->att( '#header_deleted')) { $element->delete; $first_header->set_att( '#header_deleted' => 1); } } __DATA__ <document> <header>h1</header> <header>h2</header> <header>h3</header> </document>

    Of course if you want to delete all headers after the first one, which is more likely, the code is much simpler, you just have to delete any header after the first one:

    #!/usr/bin/perl use strict; use warnings; use XML::Twig; my $twig_to_del=XML::Twig->new( twig_handlers=>{ #to_delete elements '/document/header'=> sub { $_- +>delete if $_->prev_sibling( 'header'); }, }, ) ->parse(\*DATA) ->print; __DATA__ <document> <header>h1</header> <header>h2</header> <header>h3</header> </document>
      Thanks a lot. it's works fine. i have one more clarification. I am using the below code to find "$fcnvar" not equal to blank then i need to search '//color@self="ua5"' and i should get the attribute "pnam" of that "color" element. how can i do that. can you please suggest. i am struggling here. I am getting error where i have commented the code.
      sub content_handler { my ($twig, $content)= @_; if($content->{'att'}->{'type'} eq "text") { my $selfatt=$content->att_xml_string('Self'); my $expr='//box[@textflowid="'.$selfatt.'"][@type="text"]'; my @tagnames = $twig->get_xpath($expr); for my $temp (@tagnames) { $fcnvar=$temp->att_xml_string('frameColorID'); # print "#$fcnvar#"; # if (!($fcnvar eq "")){ # my $expr='//color[@self="ua5"]'; # print "$expr"; # my @colorvalarr = $twig->get_xpath($expr); # print @colorvalarr; # print $colorvalarr[0]; # $fcnvar=$colorvalarr[0]->att_xml_string('pnam'); # } } } }

        Please, when asking for help, send a minimum, self-contained, test case, including inputs, outputs and expected outputs. It will make it possible for me (and other monks) to run the code, fix it, check that it does what you want it to do and post it back. The code above makes no sense to me, it's missing way to much context. Thanks.

        BTW, the development version of XML::Twig now raises an error on handler triggers that use the position selector, thanks for spotting the bug.