XPath - selecting descendants - difference between using // and */ - html

Can someone help me understand the difference between the two following XPath queries:
A: //table[#id="xyz"]//tr[//a[contains(text(), "Alice")]]
B: //table[#id="xyz"]//tr[*/a[contains(text(), "Alice")]]
(A) appears to select all the tr's in the table regardless of whether it has an a descendent with the text "Alice".
(B) meanwhile does what I expect in only selecting the trs with a descendents containing the text "Alice".
As an aside question, is there a more elegant way of writing the above?

You would need to use //table[#id="xyz"]//tr[.//a[contains(text(), "Alice")]] or //table[#id="xyz"]//tr[descendant::a[contains(text(), "Alice")]] to make sure that in the first expression the path in square brackets is relative to the tr. With your current //tr[//a] inside the predicate the selection //a starts from the document node, the root node, and is not relative to the tr.

//a selects all a elements anywhere in the document.
*/a selects all a elements that are grandchildren of the context node.
.//a selects all a elements that are descendants of the context node at any depth
./a (or just a) selects all a elements that are children of the context node.
It's vital to understand the notion of context. In a predicate such as tr[XXXX] the context node for evaluating XXXX is the tr element that you are testing.

Related

What is the difeerence between parent function and child function in xpath of selenium

URL==> http://demo.guru99.com/test/login.html
I use the above url for testing purpose
i try to find the web element using parent and child function in xpath,but child and parent function give me an same result,i use the below command
parent function==> $x("//div[#class='container-fluid']//parent::div")
child function==> $x("//div[#class='container-fluid']//child::div")
Observe that i use the same web element and try to fing it's parent and child element but after running the above cmd i get the similar result
Execute the cmd in cosole tab
How can have same element as a parent as well as child for particular web element
Please help in above and if not clear the question let me know i try to more describe the question
Thank you in advance
Breaking it down:
//div[#class='container-fluid']//parent::div
// select the root and all of its descendants
div[#class='container-fluid'] from all of the nodes selected in step 1., select all child div elements with an attribute class equal to 'container-fluid'
// select all nodes selected in step 2 and all of their descendants
parent::div starting from the nodes selected in step 3, select all parents of those nodes that are div elements
//div[#class='container-fluid']//child::div
// select the root and all of its descendants
div[#class='container-fluid'] from all of the nodes selected in step 1., select all child div elements with an attribute class equal to 'container-fluid'
// select all nodes selected in step 2 and all of their descendants
child::div starting from the nodes selected in step 3, select all children of those nodes that are div elements
So the reason you are getting the same result in both cases is because the div you are locating is a parent of one of the nodes selected in step 3 and a child of one of the nodes selected in step 3.
If you are just trying to select the parent or child of the container-fluid div, then get rid of the double slashes:
//div[#class='container-fluid']/parent::div
//div[#class='container-fluid']/div
The child:: axis is redundant most of the time and can be omitted in this case as I have done above.

XPath returning unexpected elements

So I have a document with multiple divs.
using the path '//div[1]' seems? to be returning multiple elements.
thoughts?
// is a shorthand in XPath for /descendant-or-self::node()/ including the leading and trailing slashes. So //div[1] fully expanded means
/descendant-or-self::node()/child::div[1]
i.e. every div element anywhere in the document that is the first div child of its respective parent.
If you want just the first div in the whole document then you need parentheses:
(//div)[1]
or use the descendant:: axis explicitly
/descendant::div[1]

How to select a child node by conditionally excluding a parents previous sibling

I have a question regarding using (what is to me) some complex XPath queries in Selenium IDE (thought they do apply to XPath in general).
Firstly, here is my scenario.
I'm writing some automated tests for a feature of a website I am working on that only certain items for sale on the website have. I'm trying to engineer the test in such a way that changes in data will not break it. Here is an abstraction of what I'm testing:
Given a set of search results, certain products within the results will have a feature (let's call the feature attributes), I want to click on the first result (which may change in the future) that has a single price and attributes.
I am using Selenium IDE 2.5.0 / FF 28.
Here is a JsFiddle I created that simulates the markup / DOM structure I have to work with (the markup cannot be changed): http://jsfiddle.net/xDaevax/3qUHB/6/
Here is my XPath query:
//div[contains(#class, 'primary')]//div[contains(#class, 'results')]//div[#class='price-range']/span[not(contains(#class, 'seperate'))]/../../..//a[#class='detail-link']
Essentially, the problem is this: All three have the same wrapping markup and css class information, but they differ in the price-range class due to the second element (the one I'm after) does not have "separate" or "minimum" CSS class elements.
I have made it this far with the XPath selector, but am stuck. I assume that when I traverse back up the DOM with the "/../..", I am losing the conditional XPath clause I previously used.
I apologize for the vagueness of the details, but due to contractual restrictions, I'm being as generic as possible.
Any suggestions on how to achieve the selection I want would be greatly appreciated. Please let me know if I need to clarify any of the requirements or steps I have tried.
Edit:
Here is a succinct description of the desired outcome.
In the markup example given, I want to select and click the link in the middle result element only. This is because the middle element has the desired "attributes" that once the link is clicked, it will take you to the product page which has additional things needing tested. That being said, the data could change: today it is the second element in the list, but maybe tomorrow it is the 7th element of 16 total elements.
My current logic for the XPath (though my solution does not work) is as follows: The element I am interested in is distinguishable from the other results because of two things: 1), it has a detail hyperlink (that will later be clicked) and 2) it does not have a range of prices (unlike the first result). Because the first result also has a hyperlink, the only difference between the two is that the first result has a minimum and separator markup element, while the second does not (my target link will always have a single price and not a range). Based on this information, I tried to write XPath that will select the first hyperlink that is not contained within an element that has a price range.
This expression will select all three div elements:
//div[contains(#class, 'primary')]
//div[contains(#class, 'results')]
//div[#class='price-range']
If I understood your requirements correctly, the price-range div must have a sibling that is an <a href> element, so we can filter out the last div by adding that restriction in a predicate: [../a[#href]]. So this expression selects only the first two divs:
//div[contains(#class, 'primary')]
//div[contains(#class, 'results')]
//div[#class='price-range']
[../a[#href]]
Now you can add one more predicate to remove the items that don't have a single price. You chose the separate class as the criterion, so we can change that last predicate and add another restriction to it: [../a[#href] and not(span[contains(#class,'separate')])]. Now your expression selects the div that you want:
//div[contains(#class, 'primary')]
//div[contains(#class, 'results')]
//div[#class='price-range']
[../a[#href] and not(span[contains(#class,'separate')])]
This is a location path, which creates a context. From this context, you can navigate anywhere you want. You can get the sibling <a href> adding a new step with its relative path: ../a. So, finally, this expression selects the link at the same level as your div:
//div[contains(#class, 'primary')]
//div[contains(#class, 'results')]
//div[#class='price-range']
[../a[#href] and not(span[contains(#class,'separate')])]
/../a
Or in one line:
//div[contains(#class, 'primary')]//div[contains(#class, 'results')]//div[#class='price-range'][../a[#href] and not(span[contains(#class,'separate')])]/../a

Normalization of a database when a row is an element of a tree

I have a MySQL table that represents an element which is a node of a tree. The element has an ID, and a parent_id element, which refers to another element in the same table (can be null for top level elements). I wish to be able to sort these elements, both locally (elements which have the same parent), and globally (I want to flatten the tree and present it as a list). I have given each element a local_sorting_key, which can sort the elements within a parent node, but I want the ability to recursively sort the whole tree.
What I've done is add a new field, global_sorting_key, which is a concatenation of the global_sorting_key of the parent (if the element has a parent), and the local_sorting_key. This allows me to recursively set a sorting key for each element, and easily get the whole table and use SQL to sort it. However, this solution is not normalized, as changes to the local_sorting_key do not produce changes in the global_sorting_key, leading to internal inconsistencies.
How do I solve my problem in a simple way, while also maintaining 3NF?

How can I access an element by using its DOM hierarchy(parent element)?

I want to access an element using a DOM hierarchy Node structure, through its parent nodes.I am trying to find the DOM hierarchy through firebug; want something like, <parent_node1>.<child_node1>.<child_node2> (not by document.getElementByID, getElementbyname) to access an element.
I want to automate a scenario like, I have column headers and corresponding values. Want to test, whether the values present under each column header, is correct...
I am thinking of using DOM as a method of automating this case...But, how can I find the DOM hierarchy...?
What I see through Inspect Element in Firebug is something like, list of events, elements and is not looking like a hierarchy node structure...Can somebody help in this regard please?
As discussed, you probably mean the DOM Element properties like element.childNodes, element.firstChild or similar.
Have a look at the DOM Element property reference over at JavaScriptKit, you'll get a good overview there how to access the hierarchy.
var currentTD = document.getElementsByTagName("td")[0];
var currentTable = document.getElementsByTagName("table")[0];
currentTD.parentNode // contains the TR element the TD resides in.
currentTable.childNodes // contains THEAD TBODY and TFOOT if present.
DOM Tables even have more properties like a rows collection and a cells collection.
A reminder of caution: Beware that these collections are live collections, so iterating over them and accessing collection.length in each iteration can be really slow because to get the length, the DOM has to be queried each time.
document.getElementById and document.getElementByTagname are using the DOM. They take an object within the DOM (specifically the document object, though you can also call both of those on elements) and return an object which is a single element or a collection of zero or more elements, respectively. That's a DOM operation. From there you can do other DOM operations on the results like getting children, parents or siblings, changing values etc.
All DOM operations come down to:
Take a starting point. This is often document though it's so often that the first thing we do is call document.getElementById or document.getElementByTagname and then work from the result that we could really consider that the starting point.
Find the element or elements we are interested in, relative to the starting point whether through startingPoint.getElementById* or startingPoing.getElementByTagname perhaps combined with some test (e.g. only working on those with a particular classname, if they have children of particular types, etc.
Read and/or change certain values, add new child nodes and/or delete nodes.
In a case like yours the starting point will be one or more tables found by document.getElementById(someID), document.getElementById(someID).getElementsByTagname('table')[0], or similar. From that table, myTable.getElementsByTagname('th') will get you the column headings. Depending on the structure, and what you are doing with it, you could just select corresponding elements from myTable.getElementsByTagname('td') or go through each row and then work on curRow.getElementsByTagname('td').
You could also just use firstChild, childNodes etc. though it's normally more convenient to have elements you don't care about filtered out by tagname.
*Since there can only be one element with a given id in a document, this will return the same if called on any element higher in the document hierarchy, so we normally just call this on document. It can be useful to call it on an element if we want to do something if the element is a descendant of our current element, and not otherwise.