我使用的是Perl v5.18.2。
我希望使用Perl的Template
模块按顺序打印哈希元素,但哈希值似乎只有在传递给Template
之后才会被排序。
use strict;
use warnings;
use Tie::IxHash;
use Template;
use Test::More;
tie my %hash, 'Tie::IxHash';
%hash = ('one' => 1, 'two' => 2, 'three' => 3);
my %vars = ('hash' => \%hash);
is_deeply(\[keys $vars{'hash'}], \['one', 'two', 'three'], 'key order');
is_deeply(\[values $vars{'hash'}], \[1, 2, 3], 'value order');
my $t = Template->new(STRICT => 1) || die(Template->error());
my $template = '[% FOREACH k IN hash %][% k.value %][% END %]';
my $output = '';
$t->process(\$template, \%vars, \$output) || die $t->error();
is($output, '123', 'templatized hash order');
done_testing(3);
这总是失败:
ok 1 - key order
ok 2 - value order
not ok 3 - templatized hash order
# Failed test 'templatized hash order'
# at t/wtf.t line 18.
# got: '132'
# expected: '123'
1..3
# Looks like you failed 1 test of 3.
我在这里缺少什么?如何在模板中保留哈希元素顺序?
答案 0 :(得分:1)
绑定的哈希在传递给不使用绑定哈希的模板工具包时会丢失其魔力,而是生成它的纯文本副本。要解决这个问题,您可以存储并传递您的密钥顺序,并使用它来按顺序提取哈希元素。
#!/usr/bin/env perl
use strict;
use warnings;
use Tie::IxHash;
use Template;
use Test::More;
tie my %hash, 'Tie::IxHash';
%hash = ('one' => 1, 'two' => 2, 'three' => 3);
is_deeply([keys %hash], ['one', 'two', 'three'], 'key order');
is_deeply([values %hash], [1, 2, 3], 'value order');
my @key_order = keys %hash;
my %vars = ( 'hash' => \%hash, key_order => \@key_order );
my $t = Template->new(STRICT => 1) || die(Template->error());
my $template = '[% FOREACH k IN key_order %][% hash.$k %][% END %]';
my $output = '';
$t->process(\$template, \%vars, \$output) || die $t->error();
is($output, '123', 'templatized hash order');
done_testing(3);
<强>输出强>
ok 1 - key order
ok 2 - value order
ok 3 - templatized hash order
1..3
答案 1 :(得分:1)
你不能那样做
当您在process
对象上调用Template
方法时,您在%vars
参数中传递的值将复制到之前的普通数据结构中它们用于构建文档
显而易见的替代方法是在调用process
之前将哈希键收集到数组中,并将其作为%vars
参数的另一个元素传递。该计划显示了这个想法
use strict;
use warnings 'all';
use Tie::IxHash;
use Template;
tie my %hash, 'Tie::IxHash';
%hash = (one => 1, two => 2, three => 3);
my @keys = keys %hash;
my %vars = (hash => \%hash, keys => \@keys);
my $t = Template->new(STRICT => 1) or die Template->error;
my $template = <<'END_TEMPLATE';
[% FOREACH k IN keys %][% hash.$k %]
[% END %]
END_TEMPLATE
my $output;
$t->process(\$template, \%vars, \$output) or die $t->error;
print $output;
1
2
3
当然,这首先消除了使用Tie::IxHash
的大部分要点,使用带有并行数组键的普通哈希可能会更好