in reply to XML::Twig replace method behaving counter-intuitively

Sorry for the late answer, I was sick.

The easy fix is that you need to cut $this_tweak before you can safely call replace. I will add a cut if the element is still part of a twig in the next version, thanks.

A couple more things: if you use warnings you will see that @matches[0] is "best written as" $matches[0] (note the $). Also the handler (the pruner sub) receives 2 parameters, the twig and the element, so you could write my( $twig, $this_tweak)= @_ (you might already know that, but I'd rather newcomers read it here ;--). And finally, using get_xpath to get the previous tweak seems a bit wasteful. You could use simply $this_tweak->previous_sibling( qq{tweak[\@name="$tweak_name"]}), or even keep an index of tweak_name => tweak_element, for direct access.

Does that help?

Replies are listed 'Best First'.
Re^2: XML::Twig replace method behaving counter-intuitively
by Anonymous Monk on Dec 04, 2007 at 18:27 UTC
    Hi, mirod! No apology for being sick is necessary. Thanks very much for replying.

    The cut did the trick! :) FYI, the thing that threw me was the difference in the wording of the documentation for the paste and replace methods, as shown on CPAN. The paste method makes it clear that you can only paste previously-cut elements (of course), but the replace method says "Sometimes it is just not possible tocut[sic] an element then paste another in its place, so replace comes in handy." I interpreted this to mean that replace was analogous to cut and paste, when you wanted to paste over another element. If I may recommend a simple change to the line that precedes it, to give it context: "Replaces an element in the tree." -> "Replaces an element in the tree with a previously cut element." (or whatever the general case is)

    Thanks for the array syntax pointer - it's a bad habit of mine, and I'll debug with -w from now on :)

    I completely missed the information that the current twig is passed into the subroutine, but I'm glad I know now.

    I did run into a problem executing the new code that looks for the previous matching element: $this_tweak->previous_sibling( qq{tweak[\@name="$tweak_name"]})

    $ ./twig_replace_test.pl Can't locate object method "previous_sibling" via package "XML::Twig:: +Elt" at ./twig_replace_test.pl line 14.
    Do I need to define that method myself?

      The next version of XML::Twig will actually cut the element if hasn't been cut before. That's easier than changing the docs ;--)

      And I am still not at 100%, I meant prev_sibling, not previous, my bad.

        For anyone keeping score, here is the final subroutune:
        # As each tweak tag is processed, this subroutine is called. Here we +will # see if any previous tweak tag had the same name attribute. If so, w +e will # replace the previous tweak tag with this new tweak tag's contents. sub pruner { my ($twig, $this_tweak) = @_; my $tweak_name = $this_tweak->att('name'); my $previous_tweak = $this_tweak->prev_sibling( qq{tweak[\@name="$ +tweak_name"]}); # If the tweak's name is found elsewhere, replace the first # instance with the latest one, then delete the latest one. if ($previous_tweak) { print "\tReplacing\n\t\t" if $debug; $previous_tweak->print if $debug; print "\n\twith\n\t\t" if $debug; $this_tweak->print if $debug; print "\n" if $debug; $this_tweak->cut; $this_tweak->replace($previous_tweak); } }
        It's working beautifully now, thank you very much!

        Get well soon :)

Re^2: XML::Twig replace method behaving counter-intuitively
by Human (Initiate) on Dec 04, 2007 at 18:28 UTC
    (posted the above anonymously by mistake)