Search code examples
xmlperlxml-twig

how to copy child or tag in xml twig by xpath?


I am new to xml twig.. I need copy from xpath to xpath, how can i do it? I was tried some method but it can't work properly, so please any one help.. how can i copy tag from xpath to xpath in xml file... how can i get this option xml::twig...

my input:

<xml>
<front>
 <sample>
<a>link <bo>ale</bo></a>
</sample>
</front>
<body>
<p>some text</p>
</body>
</xml>

I need copy tag by xpath...

from : //front/sample/ 
to : //body/

I need output as:

<xml>
    <front>
     <sample>

    </sample>
    </front>
    <body>
    <a>link <bo>ale</bo></a>
    <p>some text</p>
    </body>
    </xml>

I try:

use XML::Twig:

 my $Tag_move = XML::Twig->new(
                               twig_handlers =>{
                                        'xml' => \&Tag_Alt,
                               },
                               pretty_print => 'indented',
);
$Tag_move->parsefile(input.xml);
$Tag_move->print;

sub Tag_Alt{
        my ($Tag_move, $tagm) = @_;
             my @c = $tagm->findnodes('//front/sample/');   
             my $chi = $tagm->copy_children(@c);
             $chi->paste('first_child', $tagm->findnodes('//body/'));
}

Solution

  • You seem to be having problems with scalars vs arrays. Maybe a consequence of using jQuery in a previous life? ;--)

    In any case, your sub would work if you write this:

    sub Tag_Alt{
      my ($Tag_move, $tagm) = @_;
      my @c = $tagm->findnodes('//front/sample/');   
      my @children= map { $_->cut_children } @c;
      foreach my $child (@children) {
        $child->paste('first_child', ($tagm->findnodes('//body/'))[0]); 
      }     
    }
    

    I would write this differently though:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use XML::Twig;
    
    my @samples;
    
    my $Tag_move = XML::Twig->new(
        twig_handlers =>{ # cut and store the everything within sample
                          sample => sub { push @samples, $_->cut_children; },
                          # paste the samples within the body
                          body   => sub { foreach my $sample (@samples) 
                                            { $sample->paste( first_child => $_); }
                                        },
                        },
        pretty_print => 'indented',
        empty_tags => 'expand',   # otherwise the empty sample is output as <sample/>
    );
    $Tag_move->parsefile( "input.xml")
            ->print;
    

    BTW, do yourself a favour, and use strict and warnings. This will catch a lot of the mistakes you make. You will get errors instead of allowing unknown variables to be created silently.