Appium get xpath from element? - ios

I have code which retrieves a static text element for me fine but what I want to do is then get the xpath of that element as a string. I'm using ruby. At this point I have an array of elements I have already retrieved. Below is what I've tried but no luck.
elements.each do |element|
if element.attribute("name").include? vProblem
p "Problem found, retrieving xpath..."
# Neither of these work
p "Problem xpath is: " + element.attribute("xpath").to_s
p "Problem xpath is: " + element.xpath.to_s
end
end

I don't believe there's an easy method or setting to call which will give you the xpath value. You would have to determine it yourself. To do this, iterate through all elements on the page until you found one that (A) matched the class of the element you're looking for and (B) matches the name/value of the element.
The only issue with this approach is that it assumes that the first element matching the class and value is the correct element. If there are multiple elements with the same class and value, it will only find the first.

Related

What is the outcome of this function fun?

Integer fun(Node *p) //Linked list
while(p not equals NULL)
print p-> data
p=p->next
End loop
Well, that's a common linked list function. Here is a common linked list architecture:
The idea is that you have blocks with two contents: the actual data and the pointer to the next object of the list.
In the posted code, p is the pointer to the first element of the list.
The intention is to print all the list. So, it follows the steps:
Print the first element's data.
Update p to point to the next element.
Print this element's data.
and so on until there are no more elements.

Iterating through CSV::Rows

I'm going to preface that I'm still learning ruby.
I'm writing a script to parse a .csv and identify possible duplicate records in the data-set.
I have a .csv file with headers, so I'm parsing the data so that I can access each row using a header title as such:
#contact_table = CSV.parse(File.read("app/data/file.csv"), headers: true)
# Prints all last names in table
puts contact_table['last_name']
I'm trying to iterate over each row in the table and identify if the last name I'm currently iterating over is similar to the next last name, but I'm having trouble doing this. I guess the way I'm handling it is as if it's an array, but I checked the type and it's a CSV::Row.
example (this doesn't work):
#contact_table.each_with_index do |c, i|
puts "first contact is #{c['last_name']}, second contact is #{c[i + 1]['last_name']}"
end
I realized this doesn't work like this because the table isn't an array, it's a CSV::Row like I previously mentioned. Is there any method that can achieve this? I'm really blanking right now.
My csv looks something like this:
id,first_name,last_name,company,email,address1,address2,zip,city,state_long,state,phone
1,Donalt,Canter,Gottlieb Group,dcanter0#nydailynews.com,9 Homewood Alley,,50335,Des Moines,Iowa,IA,515-601-4495
2,Daphene,McArthur,"West, Schimmel and Rath",dmcarthur1#twitter.com,43 Grover Parkway,,30311,Atlanta,Georgia,GA,770-271-7837
#contact_table should be a CSV::Table which is a collection of CSV::Rows so in this:
#contact_table.each_with_index do |c, i|
...
end
c is a CSV::Row. That's why c['last_name'] works. The problem is that here:
c[i + 1]['last_name']
you're looking at c (a single row) instead of #contact_table, if you said:
#contact_table[i + 1]['last_name']
then you'd get the next last name or, when c is the last row, an exception because #contact_table[i+1] will be nil.
Also, inside the iteration, c is the current (or (i+1)th) row and won't always be the first.
What is your use case for this? Seems like a school project?
I recommend for_each instead of parse (see this comparison). I would probably use a Set for this.
Create a Set outside of the scope of parsing the file (i.e., above the parsing code). Let's call it rows.
Call rows.include?(row) during each iteration while parsing the file
If true, then you know you have a duplicate
If false, then call rows.add(row) to add the new row to the set
You could also just fill your set with an individual value from a column that must be distinct (e.g., row.field(:some_column_name)), such as email or phone number, and do the same inclusion check for that.
(If this is for a real app, please don't do this. Use model validations instead.)
I would use #read instead of #parse and do something like this:
require 'csv'
LASTNAME_INDEX = 2
data = CSV.read('data.csv')
data[1..-1].each_with_index do |row, index|
puts "Contact number #{index + 1} has the following last name : #{row[LASTNAME_INDEX]}"
end
#~> Contact number 1 has the following last name : Canter
#~> Contact number 2 has the following last name : McArthur

How to search an element in Nokogiri using its pointer id

In the Nokogiri documentation you can find the following:
node.pointer_id # internal pointer number
This returns the internal pointer number as an integer. However, it states nowhere how this can be used to look up a node?
I would have expected something like this:
p_id = node.pointer_id
element = page.with_pointer_id(p_id)
UPDATE...to give you an idea of the use case.
I am caching lots of html pages as Nokogiri object and scan them for specific nodes. Those nodes I save to a hash, together with the number of occurence:
{"node1" => 8}
Right now its saving the whole node as key, but it would be so much more convenient to have an identifier for it. After clustering those hashes I want to retrieve the nodes again -> thats were the id should come in.
You can do this using the #traverse method available through the Nokogiri::XML::Document instance.
Here is #traverse wrapped in your #with_pointer_id method as a singleton.
class Nokogiri::XML::Document
def with_pointer_id(p_id)
traverse {|node| return node if node.pointer_id == p_id}
end
end
Now you can do this:
element = page.with_pointer_id(p_id)
This will find the node with a pointer_id matching p_id, if it exists.

how do i limit the searchbynamelike property in grails

so here is my question what i want to do is that searchbynamelike property should give the exact result
as my string is "Hello"
so the findByNameLike("%Hello%")
it will all the result even if h is here or e or l and so on
but what i want is that if i have full hello then only it should give result
the reason being is i have hello in various places in a db table so when someone search for hello it should return all results where hello is found, but not when even if "h" is searched..
how can i achieve this in grails ...help..!!!
In your case, don't use %...% sign in string. It'll give you all results matching anywhere hello is found in your string.
use: findByNameIlike("Hello")
I have done similar search by using Criteria Query .
Just use nodes like eq or like according to your need.

xpath parent attribute of selection

Syntax of the xml document:
<x name="GET-THIS">
<y>
<z>Z</z>
<z>Z__2</z>
<z>Z__3</z>
</y>
</x>
I'm able to get all z elements using:
xpath("//z")
But after that I got stuck, I'm not sure what to do next. I don't really understand the syntax of the .. parent method
So, how do I get the attribute of the parent of the parent of the element?
Instead of traversing back to the parent, just find the right parent to begin with:
//x will select all x elements.
//x[//z] will select all x elements which have z elements as descendants.
//x[//z]/#name will get the name attribute of each of those elements.
You already have a good accepted answer, but here are some other helpful expressions:
//z/ancestor::x/#name - Find <z> elements anywhere, then find all the ancestor <x> elements, and then the name="…" attributes of them.
//z/../../#name - Find the <z> elements, and then find the parent node(s) of those, and then the parent node(s) of those, and then the name attribute(s) of the final set.
This is the same as: //z/parent::*/parent::*/#name, where the * means "an element with any name".
The // is useful, but inefficient. If you know that the hierarchy is x/y/z, then it is more efficient to do something like //x[y/z]/#name
I dont have a reputation, so I cannot add comment to accepted answer by Blender. But his answer will not work in general.
Correct version is
//x[.//z]/#name
Explanation is simple - when you use filter like [//z] it will search for 'z' in global context, i.e. it returns true if xml contains at least one node z anywhere in xml. For example, it will select both names from xml below:
<root>
<x name="NOT-THIS">
</x>
<x name="GET-THIS">
<y>
<z>Z</z>
<z>Z__2</z>
<z>Z__3</z>
</y>
</x>
</root>
Filter [.//z] use context of current node (.) which is xand return only 2nd name.

Resources