Perl 如何使用XML::Twig'传递参数和返回值;谁是处理者?
我的问题是:如何将一些参数传递给XML:Twig的处理程序,以及如何从处理程序返回结果 这是我的代码,硬编码的:Perl 如何使用XML::Twig'传递参数和返回值;谁是处理者?,perl,xml-twig,Perl,Xml Twig,我的问题是:如何将一些参数传递给XML:Twig的处理程序,以及如何从处理程序返回结果 这是我的代码,硬编码的: 如何通过使用参数$counter\u name,$type,$id来实现这一点?如何返回字符串列表的结果?谢谢(很抱歉,我没有在这里发布xml文件,因为我在这方面遇到了一些麻烦。中的任何内容都将被忽略) 免责声明:我自己没有使用过Twig,所以这个答案可能不是惯用的——它是一个通用的“如何在回调处理程序中保持状态”答案 将信息传入和传出处理程序的三种方式是: 一个。处于静态位置的状
如何通过使用参数$counter\u name
,$type
,$id
来实现这一点?如何返回字符串列表的结果?谢谢(很抱歉,我没有在这里发布xml文件,因为我在这方面遇到了一些麻烦。<和>中的任何内容都将被忽略)
免责声明:我自己没有使用过Twig,所以这个答案可能不是惯用的——它是一个通用的“如何在回调处理程序中保持状态”答案 将信息传入和传出处理程序的三种方式是: 一个。处于静态位置的状态
package TwigState;
my %state = ();
# Pass in a state attribute to get
sub getState { $state{$_[0]} }
# Pass in a state attribute to set and a value
sub setState { $state{$_[0]} = $_[1]; }
package main;
sub parse_a_counter { # Better yet, declare all handlers in TwigState
my ($twig, $element) = @_;
my $counter = TwigState::getState('counter');
$counter++;
TwigState::setState('counter', $counter);
}
两个。在某个“状态”成员中$t(XML::Twig对象)本身所持有的状态
# Ideally, XML::Twig or XML::Parser would have a "context" member
# to store context and methods to get/set that context.
# Barring that, simply make one, using a VERY VERY bad design decision
# of treating the object as a hash and just making a key in that hash.
# I'd STRONGLY not recommend doing that and choosing #1 or #3 instead,
# unless there's a ready made context data area in the class.
sub parse_a_counter {
my ($twig, $element) = @_;
my $counter = $twig->getContext('counter');
# BAD: my $counter = $twig->{'_my_context'}->{'counter'};
$counter++;
TwigState::setState('counter', $counter);
$twig->setContext('counter', $counter);
# BAD: $twig->{'_my_context'}->{'counter'} = $counter;
}
# for using DIY context, better pass it in with constructor:
my $twig = new XML::Twig(TwigRoots => $roots,
TwigHandlers => $handlers
_my_context => {});
三个。使处理程序a保持这种状态最简单的方法是使
\uuuu parse\u a\u counter\uuuu>返回一个子(即闭包)并将结果存储在全局变量中。例如:
use strict;
use warnings;
use XML::Twig;
our @results; # <= put results in here
sub parse_a_counter {
my ($type, $index) = @_;
# return closure over type & index
return sub {
my ($twig, $counter) = @_;
my @report = $counter->children( qq{report[\@type="$type"]} );
for my $report (@report) {
my @stringSet = $report->children( qq{stringSet[\@index="$index"]} );
for my $stringSet (@stringSet) {
my @string_list = $stringSet->children_text( 'string' );
push @results, \@string_list;
}
}
};
}
my $roots = { 'counter[@name="music"]' => 1 };
my $handlers = { counter => parse_a_counter( "month", 4 ) };
my $twig = XML::Twig->new(
TwigRoots => $roots,
TwigHandlers => $handlers,
)->parsefile('counter_test.xml');
这正是我所期待的 将参数传递给处理程序的最简单、最常用的方法是使用闭包。这是一个大词,但概念很简单:您像这样调用处理程序tag=>sub{handler(@\u,$my\u arg)}
,$my\u arg
将被传递给处理程序。对这个概念有更详细的解释
下面是我将如何编写代码。我使用Getopt::Long
进行参数处理,并使用qq{}
代替包含XPath表达式的字符串周围的引号,以便能够使用表达式中的引号
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
use Getopt::Long;
# set defaults
my $counter_name= 'music';
my $type= 'month';
my $id= 4;
GetOptions ( "name=s" => \$counter_name,
"type=s" => \$type,
"id=i" => \$id,
) or die;
my @results;
my $twig= XML::Twig->new(
twig_roots => { qq{counter[\@name="$counter_name"]}
=> sub { parse_a_counter( @_, $type, $id, \@results); } } )
->parsefile('counter_test.xml');
print join( "\n", @results), "\n";
sub parse_a_counter {
my ($twig, $counter, $type, $id, $results) = @_;
my @report = $counter->children( qq{report[\@type="$type"]});
for my $report (@report){
my @stringSet = $report->children( qq{stringSet[\@index="$id"]});
for my $stringSet (@stringSet){
my @string_list = $stringSet->children_text('string');
push @$results, @string_list;
}
}
$counter->purge; # free the memory of $counter
}
@莉莉07:欢迎来到SO。我格式化了您的代码,您可以通过将XML包含在反勾号中来包含它。如果我犯了错误,请随意编辑。我本来打算稍后添加一个闭包示例,但看起来draegtun在另一个答案中击败了我
<?xml version="1.0" encoding="UTF-8"?>
<root>
<counter name="music">
<report type="week">
<stringSet index="4">
<string>music week 4</string>
</stringSet>
</report>
</counter>
<counter name="xmusic">
<report type="month">
<stringSet index="4">
<string>xmusic month 4</string>
</stringSet>
</report>
</counter>
<counter name="music">
<report type="month">
<stringSet index="4">
<string>music month 4 zz</string>
<string>music month 4 xx</string>
</stringSet>
</report>
</counter>
</root>
[
[
'music month 4 zz',
'music month 4 xx'
]
];
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
use Getopt::Long;
# set defaults
my $counter_name= 'music';
my $type= 'month';
my $id= 4;
GetOptions ( "name=s" => \$counter_name,
"type=s" => \$type,
"id=i" => \$id,
) or die;
my @results;
my $twig= XML::Twig->new(
twig_roots => { qq{counter[\@name="$counter_name"]}
=> sub { parse_a_counter( @_, $type, $id, \@results); } } )
->parsefile('counter_test.xml');
print join( "\n", @results), "\n";
sub parse_a_counter {
my ($twig, $counter, $type, $id, $results) = @_;
my @report = $counter->children( qq{report[\@type="$type"]});
for my $report (@report){
my @stringSet = $report->children( qq{stringSet[\@index="$id"]});
for my $stringSet (@stringSet){
my @string_list = $stringSet->children_text('string');
push @$results, @string_list;
}
}
$counter->purge; # free the memory of $counter
}