高级perl语法 - Mojo :: DOM

时间:2012-10-10 12:16:44

标签: perl dom syntax html-parsing mojolicious

我正在尝试理解一些高级(对我来说)perl语法,用于在this tutorial之后使用DOM进行html解析:

say "div days:";
say $_->text for $dom->find('div.days')->each;

say "\nspan hours:";
say $_->text for $dom->find('span.hours')->each;

这种语法是什么意思?这是什么样的循环?建筑经典如下:for(i=0;i<10;i++){ code }不是:{code} for (some_condition)

此外,“每个”关键字的含义是什么?它是否与each Perl builtin function有共同之处,或者它是否特定于Mojo :: DOM?我想如果each在Mojo :: Dom下面,那么应该在Mojo :: DOM主页上提及它。但我没有在methods section of their site下找到each的任何提及,所以它必须是Perl的内置函数。但是,这个内置each函数的语法完全不同 - 这怎么可能?

教程页面的另一个例子

say "Open Times:";
say for $dom->find('div.openTime')
            ->map(sub{$_->children->each})
            ->map(sub{$_->text})
            ->each;

mapsub方法相同的问题。

  • 那些“Perlish”代码可以用更“C风​​格”的方式重写,以便我能理解吗?
  • 最重要的是:如何列出所有方法的参数并返回Mojo :: DOM中包含的值?它必须以某种方式完成,因为我读到即使对于Perl,也有IDE具有intellisense(自动完成),因此这个IDE必须知道方法返回值类型等。

3 个答案:

答案 0 :(得分:9)

say "Open Times:";
say for $dom->find('div.openTime')
            ->map(sub{$_->children->each})
            ->map(sub{$_->text})
            ->each;

所有这些关键字(findmapeach)实际上是非关键字,而是来自Mojo :: DOM的方法。您可以通过->运算符识别它们。

在这种情况下,有几个methods have been chained together。只有当每个人再次返回其对象(在此示例中为$dom)时,才有可能。这种链通常用于JavaScript,特别是像jQuery这样的现代框架。它使代码易于阅读并节省操作。

基本上,您在链中应用多个交易。

  1. find所有元素'div.openTime'
  2. map(用每个东西填充)给定的子(这是一个实际的Perl sub):
    1. 将当前元素的所有children作为集合
    2. 并列出它们的each(如,返回数组)
  3. map他们有一个给定的子:
    1. 从元素中提取text内容
  4. 并列出其中的each
  5. 所有这些都包含在后缀foreach中(如@Quentin所述)。 say是您可以使用use features qw(say)加载的功能。它结合了print和换行符。

    现在可能更清楚地发生了什么:

    my $collection1 = $dom->find('div.oopenTime');
    
    my $collection2 = $collection1->map(
      sub {
        my $collection = $_->children;
        return $collection->each;
      }
    );
    
    my collection3 = $collection2->map(
      sub {
        return $_->text;
      }
    );
    
    foreach my $text ($collection3) {
      say $text;
    }
    

    提供自动完成功能的IDE通常会扫描相关代码以了解对象具有的方法。查看How do I list available methods on a given object or package in Perl?或阅读模块的代码。更好:阅读文档

答案 1 :(得分:5)

  

这种语法意味着什么,这里发生了什么?

这是postfix for loop

for (@foo) {
    say $_
}

可以写成

say $_ for @foo;
  

“每个”关键字在此上下文中的含义

a method on the object。它返回Mojo :: Collection中的事物列表。

答案 2 :(得分:3)

似乎其他答案已经解释了我在教程帖子中写的内容。这就是说我想补充说我已经掌握了另一个名为pluck的Mojo :: DOM(实际上在Mojo :: Collection类中)的有用方法。这种方法降低了

的视觉复杂性
->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对象,这意味着pluck的返回将是集合的集合。为了展平结构,我需要在each调用的结果上调用children,因此我无法删除该->map次调用。

然而,现在我想知道我是否无法一起避免这种麻烦? Mojo :: DOM对CSS3 selectorsw3schools reference)有很好的支持,我可能尝试的一件事就是不直接选择父(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有很好的(如果有时候是过于宽泛的)文档。启动here以了解整个系统。特别是阅读Mojo::DOMMojo::Collection应该足以处理DOM解析。我认为您的部分问题是您没有注意到DOM和Collection对象的相互依赖性,因此您错误地认为所有方法调用都在DOM对象上。仔细阅读后,您将看到一些DOM方法(返回的那些方法可能多于一个结果)返回Collection对象,而find就是这样一种方法。