2014-09-18 2 views
4

Мне нужно найти значение, если атрибут id всех элементов <div>, у которых есть ребенок <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 нет чего-то вроде positive-lookahead Мне нужно несколько раз искать 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-стилей и parent метод Mojo :: DOM в:

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 

Или, если вы знаете, что это только первый такой ДИВ, что вы хотите, то следующий будет работать:

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

YES! Я несколько упускал из виду «первого ребенка» и «nth-child» .. Thanx.Подтвердите это, потому что это решение Mojo :: DOM, которое я уже знаю (несколько). – cajwine

3

К сожалению, Mojo::DOM не поддерживает XPath выражений, а также CSS, так как это очень естественное выражение в первом.

Возможно, вы захотите перейти на HTML::TreeBuilder::XPath. Код будет выглядеть следующим образом. Он использует выражение XPath

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

который запрашивает атрибут id любого div элемента в документе, который содержит, по меньшей мере, одного ребенка и локальное имя первого ребенка span.

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

+0

@ cajwine: Прошу прощения. Я просто наткнулся на это, когда перечитывал вопрос. – Borodin

+0

WOW! Отлично. ;) Спасибо. ;) Кажется, нужно будет изучить Xpath ... – cajwine

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'; 
Смежные вопросы