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

Dear XML::Twig guru's:
Consider the sample XML below. How to get only the element 'Title' which is having it's 'Name' attribute as 'Advanced Perl Programming' & how to modify it to 'Advanced Perl'?
<Books> <Titles Mode="List"> <Title Name="Programming Perl"/> <Title Name="Advanced Perl Programming"/> <Title Name="Learning Perl on Win32 Systems"/> </Titles> </Books>

Thanks!

Replies are listed 'Best First'.
Re: XML::Twig Question
by GrandFather (Saint) on Aug 15, 2005 at 21:30 UTC

    See XML::Twig 101 in the XML::Twig documentation. If you have a particular problem with your code post the code here and describe the problem.


    Perl is Huffman encoded by design.
      Sir, I read the documentation for XML::Twig. But I have the following problem in achieving the required results.
      I have "books.xml" file with the following content.
      <Books> <Titles Mode="List"> <Title Name="Programming Perl"/> <Title Name="Advanced Perl Programming"/> <Title Name="Learning Perl on Win32 Systems"/> </Titles> </Books>
      I have the following code to access Title element with Name => 'Advanced Perl Programming' !
      my $filtername = 'Advanced Perl Programming'; my $books_tree= new XML::Twig(twig_roots => {Title[@Name= "$filtername +"] => 1}); $books_tree-> parsefile('books.xml'); $books_tree->set_att(Name => 'Advanced Perl');
      syntax error at Books.pl line 56, near "Title[" Global symbol "@Name" requires explicit package name at Books.pl line 56.
      Execution of Books.pl aborted due to compilation errors.
      Please help! Thanks
        #! /usr/bin/perl -w use strict; use warnings; use XML::Twig; my $filtername = 'Advanced Perl Programming'; my $books_tree= new XML::Twig(); $books_tree->parsefile('books.xml'); my @title = $books_tree->get_xpath(qq[//Title[\@Name="$filtername"]]); $_->set_att(Name => 'Advanced Perl') for @title; $books_tree->print();

        Step 1 - XPaths are strings, not perl data structures. Step 2 - I'm not too familiar with twig roots, so I load the entire data structure into memory, play with it, then print it back out. If you have a huge data structure that you want to stream, then we can start from here and move it back into twig roots that can parse/modify/output in a single statement, streaming and purging as you go.

        Hope that helps.

        Your example code is close, just not quite there yet.
        use strict; use XML::Twig; my $parser = new XML::Twig( twig_print_outside_roots => 1, twig_roots => { 'Title[@Name="Advanced Perl Programming"]' => sub { my ( $tree, $element ) = @_; $element->set_att( Name => 'Advanced Perl' ); $element->print; } } ); $parser->parse_file('books.xml');
        Notice a couple of things I did differently:
        - Put your twig_roots key in single quotes. Since you're using a '@' to select an element with an attribute, you don't want Perl to think you're trying to throw a variable name in there.
        - Rather than specifying your twig_roots value as a 1, use either a reference to a sub or an anonymous sub as I did above. This gives you a lot more flexibility to do what you want. Inside this sub, is where we want to change the "Name" attribute.
        - Specify twig_print_outside_roots so that it prints the rest of the document along with the twig_root you've specified

        That should do what you were attempting.

        --Brian

        What do you intend {Title[@Name= "$filtername"] => 1} to do? @Name is an array, but it does not appear in the code fragment except here. I suspect it is not declared anywhere, and doesn't seem to make sense here in any case.


        Perl is Huffman encoded by design.