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

When you run XML::Parser using the Start, End and Char handlers, the parameters you get out are predetermined: the object, the tag & a hash of attributes. I guess this means you can't pass arguments to the handlers then, eg
my $p = new XML::Parser (Handlers => {Start => \&hdl_start(@arr), etc} +);

However, the following seems to be working fine for me (obviously it doesn't do anything, but it shows that the variables are being set from the subroutine), and I'm a bit concerned about why:

use strict; use XML::Parser; my ($tag, $name); my $p = new XML::Parser (Handlers => {Start => \&hdl_start, Default => \&hdl_def}); $p->parsefile('test.xml'); print "$tag, $name\n"; sub hdl_start { my ($p, $elt, %atts) = @_; $tag = $elt; $name = $atts{'name'}; } sub hdl_def { }
Can someone who knows about scope tell me if I'm doing a very bad thing?

Replies are listed 'Best First'.
Re: Variable scope with XML::Parser
by zby (Vicar) on Mar 17, 2003 at 11:04 UTC
    That is a strange question. The answer is inside. The hdl_start subroutine is called, from inside of the library, with the three arguments: the object, the tag & a hash of attributes (if you count that hash as one), it then sets the global $tag and $name variables. So there is no problem with your code.
      OK, so global variables, which usually get a right slagging off, are the only solution here?
        Ah that! For sure you can resolve this for many ways. Here is one (it might be a bit convoluted, I admit):
        my $p = new XML::Parser (Handlers => {Start => sub{hdl_start($tag, $na +me, @_)}, ...
        and
        sub hdl_start { $_[0] = $_[2]; $_[1] = $_[3]; }
        What I use here is an anonymous subroutine as the handler, and I've changed the hdl_start subroutine to change it's two first parameters ($_[0] and $_[1]).
        Have just read the Streams chapter in Perl and XML (a book I highly reccomend), I offer the following solution - you can pass a class to XML::Parser instead of the specific handlers. You can then have the class maintain the state, instead of global variables.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        OK, so global variables, which usually get a right slagging off, are the only solution here?

        Well, you can use closures to avoid globals, but a better solution is to not use XML::Parser directly, but use SAX instead. Or depending on your application, an even better solution might be to use a higher level module like XML::Twig or XML::XPath (etc).

Re: Variable scope with XML::Parser
by PodMaster (Abbot) on Mar 18, 2003 at 10:35 UTC
    #!/usr/bin/perl use strict; use warnings; use XML::Parser; use Data::Dumper; my $p = XML::Parser->new(); print Dumper($p); $p->{"\0_pong"} = "ping"; die Dumper($p); __END__
    Can you see the advice? Be sure to pick something unique, like $p->{"My Options"}.


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
    ** The Third rule of perl club is a statement of fact: pod is sexy.