Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

XML::Parser Object Orientation problem

by shug94 (Sexton)
on Aug 28, 2009 at 08:49 UTC ( [id://791855]=perlquestion: print w/replies, xml ) Need Help??

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

I find that XML::Parser works really well for parsing XML files. The problem is that if I try to use XML::Parser from within a Perl Class, then it cannot alter any of the fields of that class.

Generally the first argument passed to functions in Perl classes is an instance of the class (basically a 'this' pointer).

However when using XML:Parser, I define a series of handler functions, which are passed to the parser object during construction, like so:
sub parse() { my ($currentObject) = @_; my $parser = new XMLParser(Handlers => { Init => \&handleDocumentInit, Start => \&handleStartTag, End => \&handleEndTag, Char => \&handleCharacterStrings, Default => \&handleDefault,}); $parser->parse($currentObject->{xmlAsScalar}); }


And these handler functions are NOT passed an instance of the current object, but are passed an instance of expat, the underlying XML parsing engine. As such, when I have finished parsing a tag, I cannot add its information to the variables of the current object, because I have no reference to the current object. My only option appears to be adding them to a variable with a package scope. (i.e. if my package is MyXMLProcessor, then I can store the results in %MyXMLProcessor::xmlTagContainer or somesuch)

The problem arises in that my code could get called in rapid succession in parallel. Could the two copies of %MyXMLProcessor::xmlTagContainer overwrite each other and cause issues? My scripts are sitting on an Apache HTTP Server, and are started by HTTP Requests from an agent external to the server.

My other idea is to have a package level hash, with a key that is the Expat instance, then each instance of Expat (which should be unique) gets its own copy of the container variable to fill. Is this idea legit?

And my last alternative is to either use a different XML Parser, or to override the functionality of this one to accept an additional parameter, the current object. Any suggestions?

Replies are listed 'Best First'.
Re: XML::Parser Object Orientation problem
by GrandFather (Saint) on Aug 28, 2009 at 09:22 UTC

    The general trick to solve this issue is to use an anonymous sub as a shim. Consider:

    Start => sub {$self->handleStartTag (@_)},

    If you have extra parameters you want to pass to the handler you can include those before @_ (after works too if you can guarantee the length of @_, but that's generally not a safe thing to assume).


    True laziness is hard work
      I have tried doing this in a little practise program, and I am still getting stuck.

      Please forgive my Perl newb-dom.

      Here is the error I am getting, and it doesn't really make too much sense to me, given that I am not constructing a new ShimPractise on that line:
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] Premature end of script headers: SBG_ReceivedMessageListener.pl
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] Not enough arguments for ShimPractise::new at ShimPractise.pm line 26, near ");"\r
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] Compilation failed in require at SBG_InitiateRetrieveLoggedEventDataRequestHandler.pm line 8.\r
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] BEGIN failed--compilation aborted at SBG_InitiateRetrieveLoggedEventDataRequestHandler.pm line 8.\r
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] Compilation failed in require at C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/SBG_ReceivedMessageListener.pl line 5.\r
      [Sun Aug 30 10:30:50 2009] [error] [client 127.0.0.1] BEGIN failed--compilation aborted at C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/SBG_ReceivedMessageListener.pl line 5.\r


      And here is the code:

      Any idea why this gives me such a confusing error message? Is the XML::Parser trying to construct a new instance of ShimPractise when it calls the handleStartTag function?

      Any help is much appreciated, cheers,
      Shug

        Don't use Perl prototype subs - they don't do what you think they do and they probably do things you don't expect.

        Calls to new should be of the form Package->new (...). You need to fix the calls to new for both ShimPractise and XML::Parser (which you wrote as XMLParser in the code btw).

        With those bugs fixed and print $shimString; appended your code generates:

        Number of Tags: 3<BR> Tags: Tag1 Tag2 Tag3<BR>

        True laziness is hard work
Re: XML::Parser Object Orientation problem
by bluescreen (Friar) on Sep 08, 2009 at 13:15 UTC

    I had same problem i fixed it by creating subclasses of XML::Parser

    package MyParser; use strict; use base qw(XML::Parser); sub my_start { my ($self, $element, %attributes) = @_; $self->{_local_variable} = $something }

    make sure the instance variables names do not collide with XML::Parser instance variables, I'd suggest you to use a prefix for your variables like __ or anything else

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://791855]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2024-04-23 07:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found