构建“内省”精神嵌套的 html 表
这是我使用 Perl 中的模板工具包编写的内容,但它更像是一个通用算法问题。我的基本问题是,给定这样的数据结构:
my @array = (
[qw /00 01/],
[qw /10/],
[qw /20 21/],
[qw /30 31 32 33 /],
);
我需要这样的输出(为了说明而简化):
<00>
<10>
<20> <30>(00/10/20/30)</30> <31>(00/10/20/31)</31>
<32>(00/10/20/32)</32> <33>(00/10/20/30)</33>
</20>
<21> <30>(00/10/21/30)</30> <31>(00/10/21/31)</31>
<32>(00/10/21/31)</32> <33>(00/10/21/31)</33>
</21>
</10>
</00>
<01>
<10>
<20> <30>(01/10/20/30)</30> <31>(01/10/20/31)</31>
<32>(01/10/20/32)</32> <33>(01/10/20/33)</33>
</20>
<21> <30>(01/10/21/30)</30> <31>(01/10/21/31)</31>
<32>(01/10/21/32)</32> <33>(01/10/21/33)</33>
</21>
</10>
</01>
这是嵌套 html 表的简化示例,它们是真正的输出。中心节点的路径实际上是调用另一个子例程的参数,以用数据填充嵌套表。我相当确定原始数组结构的转置将会有用,所以我写了 Array::Transpose::Ragged 并于今天早些时候在 CPAN 上发布。
我管理了一个从内到外构建嵌套结构的实现(使用perl的模板工具包 -见下文),但是当我到达结构的外部部分时,我不再有机会在中心节点填充所需的数据。这是该实现的价值:关于
[% SET inner = "(path data should go here)" %]
[% MACRO process_groups(line, inner) BLOCK %]
[% FOREACH l IN line %]
<[% l %]>[% inner %]</[% l %]>
[% END %]
[% END %]
[% WHILE (x = records.pop) %]
[% inner = process_groups(x, inner) %]
[% END %]
[% inner %]
我应该采取的方法的任何建议,以获得正确的
更新:
出于兴趣,我想我应该把已接受答案的 TT 版本放上来。有点棘手,因为 TT 不像 perl 那样灵活,但这里是:
#!/usr/bin/env perl
use warnings;
use strict;
use Template;
my $template = Template->new();
my @array = (
[ qw/00 01/ ], [ qw/10/ ],[ qw/20 21/ ], [ qw/30 31 32 33/ ]);
my $stash = { records => \@array, };
$template->process(\*DATA, $stash) || die $template->error(), "\n";
__END__
[% MACRO print_output(data, path_elements) BLOCK; %]
[% current = data.0; remaining = data.slice(1); %]
[% FOREACH d IN current %]
<[% d %]>
[% IF remaining.size > 0 %]
[% path_elements.push(d); print_output(remaining, path_elements); %]
[% SET discard = path_elements.pop %]
[% ELSE %]
([% path_elements.join('/') _ '/' _ d %])
[% END %]
</[% d %]>
[% END %]
[% END %]
[% SET path = []; print_output(records, path) %]
更好的是,这是 TT 中实际的嵌套表结构:
[% MACRO print_output(data, path_elements) BLOCK; %]
<table> <tr>
[% current = data.0; remaining = data.slice(1); %]
[% FOREACH d IN current %]
<th>[% d %]</th>
[% END %] </tr>
<tr>
[% FOREACH d IN current %]
[% IF remaining.size > 0 %]
<td id="[% d %]">[% path_elements.push(d); print_output(remaining, path_elements); %]</td>
[% SET discard = path_elements.pop %]
[% ELSE %]
<td>([% path_elements.join('/') _ '/' _ d %])</td>
[% END %]
[% END %]
</tr></table>
[% END %]
[% SET path = []; print_output(records, path) %]
This is something I'm writing using the Template Toolkit in Perl, but it's more a generic algorithm problem. My basic problem is that given a data structure like this:
my @array = (
[qw /00 01/],
[qw /10/],
[qw /20 21/],
[qw /30 31 32 33 /],
);
I need output like this (simplified for illustration):
<00>
<10>
<20> <30>(00/10/20/30)</30> <31>(00/10/20/31)</31>
<32>(00/10/20/32)</32> <33>(00/10/20/30)</33>
</20>
<21> <30>(00/10/21/30)</30> <31>(00/10/21/31)</31>
<32>(00/10/21/31)</32> <33>(00/10/21/31)</33>
</21>
</10>
</00>
<01>
<10>
<20> <30>(01/10/20/30)</30> <31>(01/10/20/31)</31>
<32>(01/10/20/32)</32> <33>(01/10/20/33)</33>
</20>
<21> <30>(01/10/21/30)</30> <31>(01/10/21/31)</31>
<32>(01/10/21/32)</32> <33>(01/10/21/33)</33>
</21>
</10>
</01>
This being a simplified example of the nested html tables that are the real output. The path at the central nodes are actually the arguments to be called to another subroutine to populate the nested tables with data. I'm fairly certain that a transpose of the original array structure will be useful, so I wrote Array::Transpose::Ragged and released it on CPAN earlier today.
I managed an implementation which builds the nested structure from the inside to the outside (using perl's Template Toolkit - see below), but by the time I get to the outer parts of the structure I no longer have the opportunity to populate the required data at the central nodes. Here's that implementation for what it's worth:
[% SET inner = "(path data should go here)" %]
[% MACRO process_groups(line, inner) BLOCK %]
[% FOREACH l IN line %]
<[% l %]>[% inner %]</[% l %]>
[% END %]
[% END %]
[% WHILE (x = records.pop) %]
[% inner = process_groups(x, inner) %]
[% END %]
[% inner %]
Any suggestions for the approach I should be taking to get this right
UPDATE:
For interest, I thought I'd put the TT version of the accepted answer up. A little tricky because TT isnt quite as flexible as perl, but here goes:
#!/usr/bin/env perl
use warnings;
use strict;
use Template;
my $template = Template->new();
my @array = (
[ qw/00 01/ ], [ qw/10/ ],[ qw/20 21/ ], [ qw/30 31 32 33/ ]);
my $stash = { records => \@array, };
$template->process(\*DATA, $stash) || die $template->error(), "\n";
__END__
[% MACRO print_output(data, path_elements) BLOCK; %]
[% current = data.0; remaining = data.slice(1); %]
[% FOREACH d IN current %]
<[% d %]>
[% IF remaining.size > 0 %]
[% path_elements.push(d); print_output(remaining, path_elements); %]
[% SET discard = path_elements.pop %]
[% ELSE %]
([% path_elements.join('/') _ '/' _ d %])
[% END %]
</[% d %]>
[% END %]
[% END %]
[% SET path = []; print_output(records, path) %]
And even better here's the actual nested table structure in TT:
[% MACRO print_output(data, path_elements) BLOCK; %]
<table> <tr>
[% current = data.0; remaining = data.slice(1); %]
[% FOREACH d IN current %]
<th>[% d %]</th>
[% END %] </tr>
<tr>
[% FOREACH d IN current %]
[% IF remaining.size > 0 %]
<td id="[% d %]">[% path_elements.push(d); print_output(remaining, path_elements); %]</td>
[% SET discard = path_elements.pop %]
[% ELSE %]
<td>([% path_elements.join('/') _ '/' _ d %])</td>
[% END %]
[% END %]
</tr></table>
[% END %]
[% SET path = []; print_output(records, path) %]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不确定我是否理解您工作的全部背景,但这里是对一般问题的探讨:
Not sure I understand the full context within which you are working, but here's a stab at the general problem:
如果您需要模板工具包解决方案,请参见下文。
Perl 代码:
TT 模板(固定)(template.tt):
If you want a Template Toolkit solution, see below.
Perl code:
TT template (fixed) (template.tt):