Nokogiri: how to find the selected option of <s

2019-09-02 14:46发布

I need to get a value of the selected HTML option:

<select  name="DisplayCurrency" id="DisplayCurrency" >
<option  value="GBP" >Pounds Sterling</option>
<option  value="EUR"  selected="selected" >Euros</option>
<option  value="CHF" >Swiss Francs</option>
<option  value="DKK" >Danish Krona</option>
<option  value="CSK" >Czech Krowns</option>
<option  value="HUF" >Hungarian Forints</option>
<option  value="PLN" >Polish Zloty</option>
</option>
</select>

I tried this using Nokogiri, but it does not work:

page.search('//select[@id="DisplayCurrency"]/option[@selected=selected]').attr('value')

标签: ruby nokogiri
2条回答
做自己的国王
2楼-- · 2019-09-02 15:27

Here's some things about what Nokogiri returns when searching and more streamlined ways to git 'er done:

search returns a nodeset, which is like an array. Be careful asking for an attribute of an node when you have a nodeset.

doc = Nokogiri::HTML(html)
doc.search('option[@selected="selected"]').class # => Nokogiri::XML::NodeSet

Access a member of a nodeset by indexing:

doc.search('option[@selected="selected"]').first.attr('value') # => "EUR"
doc.search('option[@selected="selected"]')[0].attr('value') # => "EUR"

This works but I consider it an unintended side effect:

doc.search('option[@selected="selected"]').attr('value') # => #<Nokogiri::XML::Attr:0x80427464 name="value" value="EUR">

This is the same thing but it fails with an exception:

doc.search('option[@selected="selected"]')['value']  
# ~> -:26:in `[]': can't convert String into Integer (TypeError)
# ~>    from -:26:in `<main>'

Because you want the selected option inside a tag with an ID, I'd go after it using CSS selectors. at_css, at and % return a single node, simplifying the task.

doc.at_css('#DisplayCurrency option[@selected="selected"]')['value'] # => "EUR"
doc.at('#DisplayCurrency option[@selected="selected"]')['value'] # => "EUR"
(doc % '#DisplayCurrency option[@selected="selected"]')['value'] # => "EUR"
查看更多
一纸荒年 Trace。
3楼-- · 2019-09-02 15:32

This works for me, even with the invalid markup:

require 'nokogiri'
doc = Nokogiri::XML <<ENDXML
  <select name="DisplayCurrency" id="DisplayCurrency" >
  <option value="GBP" >Pounds Sterling</option>
  <option value="EUR" selected="selected" >Euros</option>
  <option value="CHF" >Swiss Francs</option>
  <option value="DKK" >Danish Krona</option>
  <option value="CSK" >Czech Krowns</option>
  <option value="HUF" >Hungarian Forints</option>
  <option value="PLN" >Polish Zloty</option>
  </option>
  </select>
ENDXML

puts doc.css('#DisplayCurrency option[@selected="selected"]').attr('value')
#=> EUR

puts doc.at_xpath('//select[@id="DisplayCurrency"]/option[@selected="selected"]').attr('value')
#=> EUR

puts doc.at_xpath('//*[@id="DisplayCurrency"]/option[@selected="selected"]/@value').value
#=> EUR

p RUBY_VERSION, Nokogiri::VERSION
#=> "1.9.2"
#=> "1.4.4"
查看更多
登录 后发表回答