2014-09-18 79 views
4

我需要找到值,如果所有<div>元素的id属性具有<span>孩子。通过其第一个子元素的名称选择HTML元素

例如,假设这个HTML

<div id="a1">     <span> xa1 </span>  </div> 
<div id="a2"> <p>...</p>  <span> xa2 </span>  </div> 
<div id="a3">   <p> <span> xa3 </span> </p> </div> 
<div id="a4"> <p>...</p>        </div> 

<div id="b1"> </div>   <span> xb1 </span> 
<div id="b2"> </div> <p>  <span> xb1 </span> </p> 
<div id="b3"> </div> <p>.</p> <span> xb3 </span> 

我需要得到:a1,仅此而已。

因为CSS选择器没有像积极向前看我需要增量搜索HTML,但我不知道如何。

如何修改下一个来源,只能得到a1

use 5.014; 
use warnings; 

use Mojo::DOM; 

my $html = do {local $/; <DATA>}; 

my $dom = Mojo::DOM->new($html); 

for my $div ($dom->find('div')->each) { 
    #say "DIV[[$div]]"; 
    my @spans = $div->find('div > span')->each; #found a1 and a2 ;(
    say $div->attr('id') if (@spans == 1); 
} 

__DATA__ 
<div id="a1">     <span> xa1 </span>  </div> 
<div id="a2"> <p>...</p>  <span> xa2 </span>  </div> 
<div id="a3">   <p> <span> xa3 </span> </p> </div> 
<div id="a4"> <p>...</p>        </div> 

<div id="b1"> </div>   <span> xb1 </span> 
<div id="b2"> </div> <p>  <span> xb1 </span> </p> 
<div id="b3"> </div> <p>.</p> <span> xb3 </span> 

<p id="p1">    <span> xp1 </span>  </p> 
<p id="p2"> <p>...</p>  <span> xp2 </span>  </p> 
<p id="p3">   <p> <span> xp3 </span> </p> </p> 
<p id="p4"> <p>...</p>        </p> 

回答

3

你可以得到你使用CSS风格的选择和魔:: DOM的parent方法在一个稍微迂回的方式寻找元素:

use strict; 
use warnings; 
use feature ":5.10"; 
use Mojo::DOM; 

my $html = do{ local $/; <DATA>}; 

my $dom = Mojo::DOM->new($html); 

# searches for div elements with spans as the first child 
for my $div ($dom->find('div > span:first-child')->parent->each) { 
    say "id: " . $div->attr('id') if $div->attr('id'); 
} 

__DATA__ 
<div id="a1">     <span> xa1 </span>  </div> 
<div id="a2"> <p>...</p>  <span> xa2 </span>  </div> 
<div id="a3">   <p> <span> xa3 </span> </p> </div> 
<div id="a4"> <p>...</p>        </div> 

<div id="b1"> </div>   <span> xb1 </span> 
<div id="b2"> </div> <p>  <span> xb1 </span> </p> 
<div id="b3"> </div> <p>.</p> <span> xb3 </span> 

<p id="p1">    <span> xp1 </span>  </p> 
<p id="p2"> <p>...</p>  <span> xp2 </span>  </p> 
<p id="p3">   <p> <span> xp3 </span> </p> </p> 
<p id="p4"> <p>...</p>        </p> 

输出:

id: a1 

或者,如果你知道这只是你想第一个这样的DIV,那么下面将工作:

say "id: " . $dom->at('div > span:first-child')->parent->attr('id'); 
+0

是的!我有点忽略了'第一个孩子'和'第n孩子'.. Thanx。应对此,因为它是Mojo :: DOM解决方案,我已经知道(有点)。 – cajwine 2014-09-18 17:32:10

3

很可惜的是Mojo::DOM不支持XPath表达式以及CSS,因为它是在前一个很自然的表情。

你可能要考虑切换到HTML::TreeBuilder::XPath。代码看起来像这样。它使用XPath表达式

//div[*][local-name(*[1])="span"]/@id 

其中询问任何div元件的具有至少一个子和所述第一子的本地名称是span文档中的id属性。

use strict; 
use warnings; 
use 5.014; 

use HTML::TreeBuilder::XPath; 

my $tree = do { 
    local $/; 
    HTML::TreeBuilder::XPath->new_from_content(<DATA>); 
}; 

say for $tree->findvalues('//div[*][local-name(*[1])="span"]/@id'); 

__DATA__ 
<html><body> 
<div id="a1">     <span> xa1 </span>  </div> 
<div id="a2"> <p>...</p>  <span> xa2 </span>  </div> 
<div id="a3">   <p> <span> xa3 </span> </p> </div> 
<div id="a4"> <p>...</p>        </div> 

<div id="b1"> </div>   <span> xb1 </span> 
<div id="b2"> </div> <p>  <span> xb1 </span> </p> 
<div id="b3"> </div> <p>.</p> <span> xb3 </span> 

<p id="p1">    <span> xp1 </span>  </p> 
<p id="p2"> <p>...</p>  <span> xp2 </span>  </p> 
<p id="p3">   <p> <span> xp3 </span> </p> </p> 
<p id="p4"> <p>...</p>        </p> 
</body></html> 

输出

a1 
+0

Thanx,但是也打印'a1'和'a2'。正如我在问题中所说的,我只想要'a1'。 – cajwine 2014-09-18 16:19:54

+0

@cajwine:我很抱歉。当我重读这个问题时,我刚刚遇到了这个问题。 – Borodin 2014-09-18 16:22:00

+0

哇!大。 ;) 谢谢。 ;)似乎,将需要学习Xpath ... – cajwine 2014-09-18 16:22:01

0

无论是这样的:

my @spans = $div->find('div > span:first-child')->each; 
say $div->attr('id') if (@spans == 1); 

或者这样:

my @kids = $div->children; 
say $div->attr('id') if @kids and $kids[0]->type eq 'span'; 
相关问题