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')
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"
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"