Nokogiri and Xpath query - ruby

I have this Xpath query inside a loop,
//div[#class='listing_content'][#{i}]/div/div/h3/a/text()
I want to process each node individually
The problem it gives the correct nodes, but all of them at once at once.
Also when i > 1, it returns nothing at all?
for i in (1...30)
name = page.xpath("//div[#class='listing_content'][#{i}]/div/div/h3/a/text()")
puts "this is name"
puts name
#Get Business phone
phone = page.xpath("//div[#class='listing_content'][#{i}]//span[#class='business-phone phone']/text()")
puts "this is phone"
puts phone
#Get Business website(if any)
puts "this is website"
website = page.xpath("//div[#class='listing_content'][#{i}]//li[#class='website-feature']//#href")
puts website
end

Also when i > 1, it returns nothing at all?
This is the second most FAQ in XPath:
Use:
(//div[#class='listing_content'])[#{i}]/div/div/h3/a/text()
The cause of the observed behavior is that in XPath the [] has higher precedence (priority) than the // pseudo-operator.
So, in your original expression you specify that every div[#class='listing_content'] element that is the i-th child of its parent should be selected.
However, in the XML document you are working with, every div[#class='listing_content'] happens to be the first (and only) child of its parent -- therefore if i > 1 then nothing is selected.
As in any other language, in order to override the default priority, we must use brackets.

Related

get text with index number and then compare with the expected text

I need to write a method which will get text with the help of index number from popup and then i need to compare with the expected text
i.e i need to verify expected plan name is displayed at the bottom of the popup box
Setting the correct id for the query (which you can get by doing on calabash console the command query("*", :id)) on code below should do the trick. If you can't use id try to get another component property (like Android component by using query("*") ) and set the query inside theget_text calls.
def get_text(query)
query(plan_query, :text).first
end
def text_equals(text, expected_text)
unless text == expected_text
fail "#{text} not equal to #{expected_text}"
end
end
def verify_plan(index, expected_text)
plan_text = get_text("* id:'PLAN_TEXTS_ID' index:#{index}") # Can change 'id:...'' by Android class if plan does not have id
expected_text = get_text("* id:'BOTTOM_PLAN_ID'") # Same as above
text_equals(plan_text, expected_text)
end

How to make an xpath expression read through a part of the document only (Ruby/Nokogiri/xpath)

I use Ruby 1.9.3p385, Nokogiri and xpath v.1.
With help from awesome people on Stackoverflow I have come up with this xpath expression:
products = xml_file.xpath("(/root_tag/middle_tag/item_tag")
to split this XML file:
<root_tag>
<middle_tag>
<item_tag>
<headline_1>
<tag_1>Product title 1</tag_1>
</headline_1>
<headline_2>
<tag_2>Product attribute 1</tag_2>
</headline_2>
</item_tag>
<item_tag>
<headline_1>
<tag_1>Product title 2</tag_1>
</headline_1>
<headline_2>
<tag_2>Product attribute 2</tag_2>
</headline_2>
</item_tag>
</middle_tag>
</root_tag>
into 2 products.
I now wish to go through each product and extract all the product information (by extracting its leaf nodes). For that purpose I am using this code:
products.each do |product|
puts product #=> <item_tag><headline_1><tag_1>Product title 1</tag_1></headline_1><headline_2><tag_2>Product attribute 1</tag_2></headline_2></item_tag>
product_data = product.xpath("//*[not(*)]")
puts product_data #=> <tag_1>Product title 1</tag_1><tag_2>Product attribute 1</tag_2><tag_1>Product title 2</tag_1><tag_2>Product attribute 2</tag_2>
end
As you can see this does exactly what I want, exept for one thing: It reads through products instead of product.
How do I limit my search to product only? When answering, please note that the example is simplified. I would prefer that the solution "erase" the knowledge of products (if possible), beacause a then it will probably work in all cases.
Instead of:
//*[not(*)]
Use:
(//product)[1]//*[not(*)]
This selects the "leaf nodes" only under the first product element in the XML document.
Repeat this for all product elements in the document. You can get their count by:
count(//product)
The answer is to simply add a . before //*[not(*)]:
product_data = product.xpath(".//*[not(*)]")
This tells the XPath expression to start at the current node rather than the root.
Mr. Novatchev's answer, while technically correct, would not result in the parsing code being idiomatic Ruby.
You may just want:
product_data = product.xpath("*")
which will all find sub-elements of product.

how to get attribute values using nokogiri

I have a webpage whose DOM structure I do not know...but i know the text which i need to find in that particular webpage..so in order to get its xpath what i do is :
doc = Nokogiri::HTML(webpage)
doc.traverse { |node|
if node.text?
if node.content == "my text"
path << node.path
end
end
}
puts path
now suppose i get an output like ::
html/body/div[4]/div[8]/div/div[38]/div/p/text()
so that later on when i access this webpage again i can do this ::
doc.xpath("#{path[0]}")
instead of traversing the whole DOM tree everytime i want the text
I want to do some further processing , for that i need to know which of the element nodes in the above xpath output have attributes associated with them and what are their attribute values. how would i achieve that? the output that i want is
#=> output desired
{ p => p_attr_value , div => div_attr_value , div[38] => div[38]_attr_value.....so on }
I am not facing the problem in searching the nodes where "my text" lies.. I wanted to have the full xpath of "my text" node..thts why i did the whole traversal...now after finding the full xpath i want the attributes associated with the each element node that I came across while getting to the "my text" node
constraints are ::I cant use any of the developer tools available in a web browser
PS :: I am newbie in ruby and nokogiri..
To select all attributes of an element that is selected using the XPath expression someExpr, you need to evaluate a new XPath expression:
someExpr/#*
where someExpr must be substituted with the real XPath expression used to select the particular element.
This selects all attributes of all (we assume that's just one) elements that are selected by the Xpath expression someExpr
For example, if the element we want is selected by:
/a/b/c
then all of its attributes are selected by:
/a/b/c/#*

ruby block questions loop variables

comics = load_comics( '/comics.txt' )
Popup.make do
h1 "Comics on the Web"
list do
comics.each do |name, url|
link name, url
end
end
end
I am new to ruby. This is a piece of code from a ruby website.
I cant find what 'link' and 'list' keyword in the menu.
can someone explain it a little bit those two keywords, and where is the definition of those two keyword .
I am also confused on how they read the variables name and url, they are reading it by the space at the same line or what?
so if I have
Comics1 link_of_comics_site_1
Comics2 link_of_comics_site_2
Comics3 link_of_comics_site_3
so for the first iteration, name=Comics1, and url =link_of_comics_site_1
Thanks.
That's not just Ruby. That's a template for a webpage using ruby add-on methods for HTML generation.
But presumably, the result of the call to load_comics is a Hash, where the keys are names and the values are URLs. You could make one of those yourself:
my_comics_hash = { "name1" => "url1", "name2" => "url2" }
which you can then iterate over the same way:
my_comics_hash.each do |name, url|
puts "Name #{name} goes with URL #{url}"
end
In your code, it's building up an HTML list inside a popup window, but it's the same idea. The each method iterates over a collection - in this case a Hash - and runs some code on every item in that collection - in this case, each key/value pair. When you call each, you pass it a block of code inside do ... end; that's the code that gets run on each item. The current item is passed to the code block, which declares a variable to hold it inside the pipes right after the word do. Since we're iterating over key/value pairs, we can declare two variables, and the key goes in the first and the value in the second.
In ruby function, parenthesis is optional and the ";" end of statement is also optional. ej
link "click here" , "http://myweb.com"
is equivalent to :
link("click here", "http://myweb.com");
But If you have more than one statement in a line the ";" is a must, ej
link("click here1", "http://myweb.com"); link("click here2", "http://myweb.com");
In your code it could be written in
link(name, url)
or just
link(name, url);
or
link name, url
But it is highly recommended to put parenthesis around function parameters for readability unless you have other reason . The ";" is not common in ruby world .

checking if all elements in a drop down menu are present with selenium testing using ruby?

HI
how can i check if all elements in an array i created are present in a drop down menu using selenium testing?
i have something like this but dosent seem to work
ANIMALS = ["snake","cat","dog"]
def validate_all_animals_exist(selenium)
ANIMALS.each { |animal| assert selenium.is_element_present(animal), "Expected category [#{animal}] to be present" }
end
thanks in advance
You need to use the verifySelectOptions call
verifySelectOptions(selectLocator,
pattern) Generated from
getSelectOptions(selectLocator)
Arguments:
* selectLocator - an element locator identifying a drop-down menu
Returns:
an array of all option labels in the specified select drop-down
Gets all option labels in the specified select drop-down.
So it would be
assert_equal "123123", page.get_select_options("foo").join(",")

Resources