2016-05-07 16 views
1

XPathを使用してNokogiriでドキュメントを解析しています。私は構造リストの内容に興味がある:私は使用してこれをやっているXPathで他の要素を含む要素のテキストのみを取得するには?

<ul> 
    <li> 
    <div> 
     <!-- Some data I'm not interested in --> 
    </div> 
    <span> 
     <a href="some_url">A name I already got easily</a> 
     <br> 
     Some text I need to get but just can't 
    </span> 
    </li> 
    <li> 
    <div> 
     <!-- Some data I'm not interested in again --> 
    </div> 
    <span> 
     <a href="some_other_url">Another name I already got easily</a> 
     <br> 
     Some other text I need to get but just can't 
    </span> 
    </li> 
    . 
    . 
    . 
</ul> 

politicians = Array.new 
rows = doc.xpath('//ul/li') 
rows.each do |row| 
    politician = OpenStruct.new 
    politician.name = row.at_xpath('span/a/text()').to_s.strip.upcase 
    politician.url = row.at_xpath('span/a/@href').to_s.strip 
    politician.party = row.at_xpath('span').to_s.strip 
    politicians.push(politician) 
end 

これはpolitician.namepolitician.urlのために正常に動作しますが、それはpolitician.party、となると、これは<br>タグの後のテキストです。テキストを切り分けることはできません。

row.at_xpath('span').to_s.strip 

他のHTML要素を含む<span>タグのすべてのコンテンツが表示されます。

このテキストを取得する方法に関するご意見はありますか?

+0

'span/text()'を試してください。 –

+0

私はそれをして空になります。 –

+0

'to_s'と' text'の違いと、Nokogiriの 'text'メソッドを使ってXPathで' text() 'セレクタを使うタイミングを知る必要があります。私の答えを見てください。 –

答えて

4

span/text()<span>の最初のテキストノードは、スパン開始タグと<a/>要素の間にある空白(改行と空白)であるため、空を返します。代わりに次のXPathを使用してみてください:

span/text()[normalize-space()] 

このXPathは<span>

1

の直接の子である非空のテキストノードを返す必要があります私はこのようにそれを行うだろう:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<span> 
    <a href="some_other_url">Another name I already got easily</a> 
    <br> 
    Some other text I need to get but just can't 
</span> 
EOT 

doc.at('span br').next.text # => "\n Some other text I need to get but just can't\n" 

doc.at('//span/br').next.text # => "\n Some other text I need to get but just can't\n" 

結果の文字列を簡単にクリーニングする:

"\n Some other text I need to get but just can't\n".strip # => "Some other text I need to get but just can't" 

あなたのコードは、あなたが望む結果を得るためにDOMに深く十分に見ていないされている、プラスあなたが間違ったことをやっている問題:

doc.at_xpath('//span').to_s # => "<span>\n <a href=\"some_other_url\">Another name I already got easily</a>\n <br>\n Some other text I need to get but just can't\n</span>" 

to_sは同じですto_htmlを返し、ノードを元のマークアップに戻します。あなたがそのテキストを取得することはできませんコンテナではありません

doc.at_xpath('//span').text # => "\n Another name I already got easily\n \n Some other text I need to get but just can't\n" 

<br>ので、しかし:textを使用すると、タグを取り除く、近くにあなたを取得され、しかし、再び、あなたはあまりにも遠く戻って立っているだろうその後、

doc.at('span br').next.class # => Nokogiri::XML::Text 

XML/HTMLを解析し、それはあなたがしたい、実際のノードを指すように本当に重要だ、と:まだナビゲートするために使用することができ、その後、Textノードであるnextノードを取得し、それを取得適切な方法を使用してください。そうしないと、あなたが望む実際のデータを取得しようとするフープを飛び越さなければなりません。あなたが/スピンドルを折り畳むことができ

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<span> 
    <a href="some_other_url">Another name I already got easily</a> 
    <br> 
    Some other text I need to get but just can't 
</span> 
EOT 

data = doc.search('span').map{ |span| 
    name = span.at('a').text 
    url = span.at('a')['href'] 
    party = span.at('br').next.text.strip 

    { 
    name: name, 
    url: url, 
    party: party 
    } 
} 
# => [{:name=>"Another name I already got easily", :url=>"some_other_url", :party=>"Some other text I need to get but just can't"}] 

/あなたの意志にそれを曲げるために不具:すべて一緒に、私は何かのようにしてくださいすることを置く

最後に、search('//path/to/some/node/text()').textをしないでください。あなたは、キー入力やCPUを無駄にしている:

doc = Nokogiri::HTML(<<EOT) 
<p> 
    Some other text I need to get but just can't 
</p> 
EOT 

doc.at('//p')  # => #<Nokogiri::XML::Element:0x3fed0841edf0 name="p" children=[#<Nokogiri::XML::Text:0x3fed0841e918 "\n Some other text I need to get but just can't\n">]> 
doc.at('//p/text()') # => #<Nokogiri::XML::Text:0x3fed0841e918 "\n Some other text I need to get but just can't\n"> 

text()は、テキストノードを返しますが、それはテキストを返しません。

doc.at('//p/text()').text # => "\n Some other text I need to get but just can't\n" 

代わりに、あなたは鋸山をしたいと言うことでポイントがそれを得る:

doc.at('//p').text # => "\n Some other text I need to get but just can't\n" 

XPathがノードを指すことができ、それを

は、結果として、あなたは何を余儀なくされていますテキストが必要なときに助けにならないので、セレクタを単純化してください。

+0

ありがとうございました。素晴らしいレッスン!私はそれに応じて私のコードを変更し、私のお気に入りの間にこの答えを保持します。 –

+1

XML/HTMLを歩くのに時間がかかります。私はそれをディレクトリ階層のように考え、特定のディレクトリ名をループする機能を持っています。それは基本的にXPathの仕組みです。 –

関連する問題