似乎其他答案已经解释了我在教程帖子中写的内容。也就是说,我想补充一点,我已经掌握了 Mojo::DOM(实际上是 Mojo::Collection 类)中另一个有用的方法,称为pluck
. 这种方法降低了视觉复杂度
->map(sub{$_->text})
至
->pluck('text')
此外,我注意到至少我的一些each
调用是无关的,并且在列表上下文中使用的 Mojo::Collection 将自动“按我的意思做” each
。
编辑:我检查了这个,实际上当用作字符串时,元素用换行符连接。因为这不是我想要的,所以我已经回了each
电话。
这里所说的就是我现在如何编写相同的教程脚本:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.10.0;
use Mojo::DOM;
my $dom = Mojo::DOM->new(<<'HTML');
<div class="box notranslate" id="venueHours">
<h5 class="translate">Hours</h5>
<div class="status closed">Currently closed</div>
<div class="hours">
<div class="timespan">
<div class="openTime">
<div class="days">Mon,Tue,Wed,Thu,Sat</div>
<span class="hours"> 10:00 AM–6:00 PM</span>
</div>
</div>
<div class="timespan">
<div class="openTime">
<div class="days">Fri</div>
<span class="hours"> 10:00 AM–9:00 PM</span></div>
</div>
<div class="timespan">
<div class="openTime">
<div class="days">Sun</div>
<span class="hours"> 10:00 AM–5:00 PM</span>
</div>
</div>
</div>
</div>
HTML
say "div days:";
say for $dom->find('div.days')->pluck('text')->each;
say "\nspan hours:";
say for $dom->find('span.hours')->pluck('text')->each;
say "\nOpen Times:";
say for $dom->find('div.openTime')
->map(sub{$_->children->each})
->pluck('text')
->each;
请注意,我不使用该方法是->pluck('children')
因为该children
方法返回 Mojo::Collection 对象,这意味着返回 frompluck
将是集合的集合。为了展平结构,我需要调用调用each
结果,children
因此我无法删除该特定->map
调用。
但是,现在我想知道我是否不能一起避免这个麻烦?Mojo::DOM 对CSS3 选择器(w3schools 参考)有很好的支持,我可能会尝试的一件事是不div.openTime
直接选择父级(),而是在选择器中选择它的子级。
say "\nOpen Times:";
say for $dom->find('div.openTime > *')->pluck('text')->each;
所以这里有一个很好的教训:允许选择器给你几乎你想要的集合,这样你就不必在以后转换它。
要回答您的最后问题:
翻译这个
say for $dom->find('div.openTime')
->map(sub{$_->children->each})
->map(sub{$_->text})
->each;
对于更多 C-esque Perl(虽然我不会把它发挥到for(i=0;i<10;i++){ ... }
极致)它可能看起来像
my @open_times = $dom->find('div.openTime')->each;
my @all_children;
foreach my $elem ( @open_times ) {
my @children = $elem->children->each;
push @all_children, @children;
}
my @texts;
foreach my $child ( @all_children ) {
push @texts, $child->text;
}
foreach my $text ( @texts ) {
print $text . "\n";
}
我相信您会明白为什么我更喜欢 Mojo(对象链接)方式。
至于你的第二个问题:Mojolicious 有很棒的(如果有时过于冗长)文档。从这里开始了解整个系统。具体阅读有关Mojo::DOM和Mojo::Collection应该足以处理 DOM 解析。我认为您的部分问题是您没有注意到 DOM 和 Collection 对象的相互依赖关系,因此您错误地认为所有方法调用都在 DOM 对象上。当您仔细阅读时,您会看到一些 DOM 方法(返回的可能不止一个结果)返回 Collection 对象,并且find
就是这样一种方法。