Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

scope of variable

by priyo (Novice)
on May 27, 2013 at 08:58 UTC ( #1035373=perlquestion: print w/ replies, xml ) Need Help??
priyo has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
I am observing strange behavior of following sub
----------------------------------------------------------------- sub getValue($) { my ($reportFile) = @_; my $myData = 0; my $parser = new XML::Parser ( Handlers => { Start => \&hdl_start +, End => \&hdl_end, Char => \&hdl_char, Default => \&hdl_def, Final => \&hdl_final }); $parser->parsefile( $reportFile ); # The Handlers sub hdl_start{ print $d; # print1 # here I am identfying my target Cell from XML Table } sub hdl_char { # here I am collecting data ($d) from target Cell } sub hdl_end{ $myData = $d; print $d; # print2 } sub hdl_final{ print $d; # print3 } print $d; # print4 } my $m = getValue("file1"); my $n = getValue("file1"); ----------------------------------------------------------------------
On 1st call of getValue everything works fine.
On 2nd call of getValue...
print1 prints value of $d from earlier call
print2, print3 prints correct value assigned during latest call.
print4 prints 0 for $d

Please help me to identify the issue. I assumed scope of $d is limited to given call.

Regards
Priyo

Comment on scope of variable
Download Code
Re: scope of variable
by Anonymous Monk on May 27, 2013 at 09:15 UTC
Re: scope of variable
by hdb (Parson) on May 27, 2013 at 09:20 UTC

    For me, some information is missing before your puzzle can be solved:

    1. Are you running under use strict;?
    2. Where do you declare my $d;?
    3. Are you sure that your print statements are executed in order suggested? I would feel more comfortable if you had print "1:$d"; for your print1 etc. The parser might call your functions in a different order than expected or suggested by the names. (I have not checked on the documentation of XML::Parser.)

Re: scope of variable
by Anonymous Monk on May 27, 2013 at 09:35 UTC
    Why are those sub definition inside another subroutine? Did you want them to be lexically scoped? If so you should check that your version of perl makes it default behavior (ie perl6, which I suppose you're actually not using), or that the feature is enabled. But in perl 5.18 this feature is experimental, and should be used with caution. If you did not want lexical scope for you subs, which they probably do not have (pushes the sub names into the current package's namespace). Actually, I'm pretty your subs are only compiled once, and not each time you enter getValue. That may have nothing to do with your problem, but since you are speaking of scoping issues ...
      Nested subs in Perl are actually global, but they bind, as a closure to the variables for the first time the parent sub is called.

      Which is, I'm pretty sure, the root of his problem.

        Thanks, I learn something new about Perl every day. When I saw the nested subs, I thought I was looking a JavaScript for a moment! :-)

        If you spot any bugs in my solutions, it's because I've deliberately left them in as an exercise for the reader! :-)
      Thanks for your prompt response
      In my earlier post I gave simplified code, where actual function is explained in comment (#). Here is original code.

      The output of two calls as follows:

      PK_start : Sheet0 : 0, 0, 0, 0, 0
      PK_end : Sheet0 : 5 : 17 : 82 : 0 : 0
      PK_start : Sheet1 : 8, 21, 82, 0, 0
      PK_start : Sheet2 : 0, 0, 82, 0, 0
      PK_final : 0, 0, 82, 0, 0
      PK_return : 0, 0, 82, 0, 0
      APB2DCR_vPlan.ann.xml : 82
      PK_start : Sheet0 : 0, 0, 82, 0, 0
      PK_end : Sheet0 : 5 : 17 : 78 : 0 : 0
      PK_start : Sheet1 : 8, 21, 78, 0, 0
      PK_start : Sheet2 : 0, 0, 78, 0, 0
      PK_final : 0, 0, 78, 0, 0
      PK_return : 0, 0, 0, 0, 0
      APB2DCR_vPlan.pass.ann.xml : 0
      Please note return value of 3rd variable

      sub getFuncCovSummary($) { my ($reportFile) = @_; my $func = 0; my $compl = 0; my $group = 0; my $assert = 0; my $ftest = 0; my $targetSheet = ""; my $col = 0; my $row = 0; my $hvp_col = 0; my $grp_col = 0; my $ass_col = 0; my $tst_col = 0; my $plan_row = 0; my $isData = 0; my $isComment = 0; my $mergeAcross = 0; my $mergeDown = 0; my @str = (); my $parser = new XML::Parser ( Handlers => { Start => \&hdl_start +, End => \&hdl_end, Char => \&hdl_char, Default => \&hdl_def, Final => \&hdl_final +, }); $parser->parsefile( $reportFile ); # The Handlers sub hdl_start{ my ($p, $elt, %atts) = @_; return unless (($elt eq 'Worksheet') || ($elt eq 'Row') || ($elt eq 'Cell') || ($elt eq 'Comment') || ($elt eq 'Data') || ($elt eq 'ss:Data')); if ($elt eq 'Worksheet') { if ($atts{'ss:Name'} =~ /^(\d)_/) {$targetSheet = "Sheet$1";} print "PK_start : $targetSheet : $row, $col, $group, $assert, + $ftest<br>"; $row = 0; $col = 0; } return unless $targetSheet eq "Sheet0"; if ($elt eq 'Row') { $row++; $col = 0;} if ($elt eq 'Cell') { $col = $col + 1 + $mergeAcross; if ($atts{'ss:Index'} > 0) { $col = $atts{'ss:Index'};} if ($atts{'ss:MergeAcross'} > 0) {$mergeAcross = $atts{'ss:Me +rgeAcross'};} else {$mergeAcross = 0;} if ($atts{'ss:MergeDown'} > 0) {$mergeDown = $atts{'ss:MergeD +own'};} else {$mergeDown = 0;} } if ($elt eq 'Comment') { $isComment = 1;} if (($elt eq 'Data') || ($elt eq 'ss:Data')) { @str = (); $isDat +a = 1;} } sub hdl_end{ my ($p, $elt) = @_; return unless $targetSheet eq "Sheet0"; return unless (($elt eq 'Comment') || ($elt eq 'Data') || ($elt eq 'ss:Data')); if ($elt eq 'Comment') { $isComment = 0;} if (($elt eq 'Data') || ($elt eq 'ss:Data')) { if (!$isComment) { my $p = 0; my $str = join("", @str); if ($str =~ /^hvp\s+plan/) { $hvp_col = $col; } if ($str =~ /^value\w+\.Group/) { $grp_col = $col; } if ($str =~ /^value\w+\.Assert/) { $ass_col = $col; } if ($str =~ /^value\w+\.test/) { $tst_col = $col; } if (($col == $hvp_col) && ($str =~ /^plan/)) { $plan_row += $row; } if (($row == $plan_row) && ($col == $grp_col)) { $group = + sprintf("%0.f",$str*100); $p = 1;} if (($row == $plan_row) && ($col == $ass_col)) { $assert = + sprintf("%0.f",$str*100); $p = 1;} if (($row == $plan_row) && ($col == $tst_col)) { $ftest = + $str; $p = 1;} if ($p) {print "PK_end : $targetSheet : $row : $col : $gro +up : $assert : $ftest<br>";} } $isData = 0; } } sub hdl_char { my ($p, $str) = @_; return unless $targetSheet eq "Sheet0"; return unless ($isData && !$isComment); push @str, $str; } sub hdl_def { } sub hdl_final {print "PK_final : $func, $compl, $group, $assert, $f +test<br>"; } print "PK_return : $func, $compl, $group, $assert, $ftest<br>"; return ($func, $compl, $group, $assert, $ftest); }# getFuncCovSummary
        Forgot to mentioned, I have  use strict;
Re: scope of variable
by kcott (Abbot) on May 27, 2013 at 13:05 UTC

    G'day Priyo,

    Welcome to the monastery.

    Your code raised a number of issues which I'll address first. My comments assume you've posted all relevant code; however, your problem description suggests otherwise. Of course, I have no way of knowing what you've left out; just bear that in mind as you read the following. (These guidelines will help you post a better question next time: "How do I post a question effectively?".)

    • You don't declare "$d". ("use strict;" would have picked this up — see strict)
    • You don't assign a value to "$d". ("use warnings;" would have picked this up — see warnings)
    • You haven't shown any input: I have no idea what data you're processing.
    • You haven't shown your output: "everything works fine" (and similar prose) is not particularly helpful.
    • Don't use prototypes unless you really need them and know exactly what you're doing (see perlsub - Prototypes).
    • Don't use Indirect Object Syntax (see perlobj - Invoking Class Methods).
    • You create a new $parser each time getValue() is called: this is unnecessary.
    • You don't capture the return value of $parser->parsefile() (see XML::Parser - METHODS).
    • You don't read the arguments passed to your handlers (see XML::Parser - HANDLERS).
    • You define your handlers inside the getValue subroutine. I don't know what you were trying to achieve by doing this.

    Here's a basic script (along the lines that I think you want) which addresses these issues. Consider this a template for reworking your code.

    #!/usr/bin/env perl use strict; use warnings; use XML::Parser; my $parser = XML::Parser::->new(Handlers => { Start => \&hdl_start, End => \&hdl_end, Char => \&hdl_char, Default => \&hdl_def, Final => \&hdl_final, }); my @xml_files = qw{./pm_xml_parser_test_file1.xml ./pm_xml_parser_test_file2.xml +}; for (@xml_files) { _init_handler_vars('filename'); get_value($_); } sub get_value { my $file = shift; my $returned = $parser->parsefile($file); if (defined $returned) { print "Wanted content: '$returned'\n"; } else { print "Wanted content not found!\n"; } return; } # Private scope for handler variables { my ($wanted_element, $in_wanted_element, $wanted_content, $found_wanted_content); sub _init_handler_vars { $wanted_element = shift; $in_wanted_element = 0; $wanted_content = ''; $found_wanted_content = 0; return; } sub hdl_start { my ($expat, $element, $attr, @vals) = @_; if ($element eq $wanted_element) { $in_wanted_element = 1; } return; } sub hdl_end { my ($expat, $element) = @_; if ($element eq $wanted_element) { $in_wanted_element = 0; } return; } sub hdl_char { my ($expat, $string) = @_; if ($in_wanted_element) { if ($string) { $found_wanted_content = 1; $wanted_content = $string; } } return; } sub hdl_def { my ($expat, $string) = @_; # Default handler actions here return; } sub hdl_final { my ($expat) = @_; return unless $found_wanted_content; return $wanted_content; } }

    Most of what I have here should be obvious from the issues I identified (and supporting documentation) above. Note that the variables $wanted_element, $in_wanted_element, $wanted_content and $found_wanted_content are only visible to _init_handler_vars() and the handlers themselves (hdl_*()).

    Here's my (minimal) test data:

    $ cat ./pm_xml_parser_test_file1.xml <root_element> <filename>pm_xml_parser_test_file1.xml</filename> </root_element> $ cat ./pm_xml_parser_test_file2.xml <root_element> <filename>pm_xml_parser_test_file2.xml</filename> </root_element>

    Here's the output:

    $ pm_xml_parser_test.pl Wanted content: 'pm_xml_parser_test_file1.xml' Wanted content: 'pm_xml_parser_test_file2.xml'

    -- Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1035373]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2014-07-26 02:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (175 votes), past polls