I am trying to write some XML::Twig code which transforms nested elements into arithmetical expressions, e.g.:
<set> $z <add>$x $y</add> </set>
turns into
$z = $x + $y
So in order for my TwigHandlers to fire on the <add> nested inside the <set>, I recursively create a new XML::Twig and parse the small <add> element:
{ my $twig = new XML::Twig ( %constructor ) ; $twig->parse($elt->next_elt->sprint); }
and this does in fact work: my TwigHandlers notice the <add> tag and fire. However I have two different behaviors I want from my handlers. Sometimes I want them to print their output and other times I want them to append to a string.

this is controlled by a package variable called $pmode. When it is true, then the call to my print routine will print, otherwise it will append to a string. I am altering $pmode by the use of local(), but for some reason, when the TwigHandler for add fires and $pmode has been localized, it instead has the non-localized true version, when it should have the localized false version.

I print $pmode immediately before and after the call to parse in the newly created twig, and it is false in both cases, however when the TwigHandler fires and I print $pmode there, unfortunately it is true... but how this could be is confusing.

#!/usr/local/bin/perl use Data::Dumper; use XML::Twig; ++$|; our $pmode = 1; my $pstring; sub pt { my (@string) = @_; for (@string) { if ($pmode) { print $_; } else { $pstring .= $_; } } } # print expression - no semicolon at end sub pe { pt $_[0] } # print statement - semicolon at end sub ps { pt "$_[0];\n"; } # print statement demux - distribute 1 fish to each of the masses sub ps_dmux { my ($fish, @masses) = @_; map { ps "$fish $_" } @masses; } # print statement with masses as a parenthesized arguement sub ps_pare { my ($fish, @masses) = @_; ps sprintf "$fish (%s)", join ',', @masses; } my %constructor = ( StartTagHandlers => { scope => sub { print "{" }, perl => sub { my $T = $_[1]->att("binary"); printf "#!%s\n", $T }, }, TwigHandlers => { scope => sub { print "}" }, use => sub { my @p = split /\s+/, $_[1]->text; ps_dmux $_[1]->gi +, @p }, my => sub { my @p = split /\s+/, $_[1]->text; ps_pare $_[1]->gi +, @p }, print => sub { my @p = split /\s+/, $_[1]->text; ps_pare $_[1]->gi +, @p }, add => sub { my @p = split /\s+/, $_[1]->text; warn " [add pmode +: $pmode]\ "; pe join '+', @p }, set => sub { my $elt = $_[1]; my @children = $elt->children; if (@children == 1) { ps sprintf "%s = %s", split /\s+/, $elt->text } else { # children == 2 or more { local $pmode; pt $elt->next_elt->text, " = "; $elt = $elt->next_elt; warn " [else pmode : $pmode ] "; my $twig = new XML::Twig ( %constructor ) ; $twig->parse($elt->next_elt->sprint); warn " [else pmode 2 : $pmode ] "; } warn " [ non-local pmode: $pmode ]"; pt $pstring; $pstring = ''; } } } ); my $twig = new XML::Twig ( %constructor ) ; my $file = shift or die "usage: $0 perxml.xml"; $twig->parsefile($file);
and here is a sample xml file
<perl binary="/usr/bin/perl"> <use>strict warnings diagnostics</use> <scope> <my>$x $y $z</my> <set>$x 111</set> <set>$y 554</set> <set>$z <add>$x $y</add> </set> <print>$z</print> </scope> </perl>
</code>

In reply to XML::Twig recursive constructor calls and local() by princepawn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.