|
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
Re: scope of variable
by hdb (Monsignor) on May 27, 2013 at 09:20 UTC
|
For me, some information is missing before your puzzle can be solved:
- Are you running under use strict;?
- Where do you declare my $d;?
- 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.)
| [reply] [d/l] [select] |
Re: scope of variable
by Anonymous Monk on May 27, 2013 at 09:15 UTC
|
Please help me to identify the issue. I assumed scope of $d is limited to given call.
A few issues
* In the code you posted $d never has a value -- it might as well not exist
* If you used strict it would complain about $d requiring an explicit package name -- cause what is $d ? where does it come from? who sets its value?
* your sub is called getValue but all it does is print stuff
* You're using XML::Parser but you should be using XML::Twig :) use XML::Twig :) it comes with many examples/tutorials, XML::Twig, XML::LibXML, Mojo::DOM ... see Re: The best module for handling xml for examples, walkthroughs, follow my links and the links they link, like these Re: How to grab a portion of file with regex (don't)(parsing html/xml with xpath/twig/dom, because html::parser is low level), Re: How to grab a portion of file with regex (parsing html/xml with xpath/twig/dom, because xml::parser is low level), Re^4: How to grab a portion of file with regex (parsing html/xml with xpath/twig/dom, because ::parser is low level)
| [reply] |
Re: scope of variable
by kcott (Archbishop) 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'
| [reply] [d/l] [select] |
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 ... | [reply] |
|
|
| [reply] |
|
|
| [reply] |
|
|
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
| [reply] [d/l] |
|
|
Forgot to mentioned, I have use strict;
| [reply] [d/l] |
|
|
|
|
|
|