why wouldn't this XPath example work? - xpath

I am trying to locate the first <th> element under a <table> element. The table element is tagged with a particular id, and is locatable when I only look as far as that tag.
But when I try to go a little further down and search using the XPath below, it returns a null element. The '/th[0]' is to say: return the first <th> element, under the element that is tagged with the particular id.
In the example, the id value is populated prior to the search:
"//*[#id='{0}']/th[0]"

XPath indexes are 1-based. Try: //*[#id='{0}']/th[1]
This trips me up all the time as well; too much time spent with 0-based indexing in C, C++, etc.

Related

What XPath expression is able to fetch rows from a table regardless of presence of implicit tbody tag in DOM? [duplicate]

As in this Stack Overflow answer imagine that you need to select a particular table and then all the rows of it. Due to the permissiveness of HTML, all three of the following are legal markup:
<table id="foo"><tr>...</tr></table>
<table id="foo"><tbody><tr>...</tr></tbody></table>
<table id="foo"><tr>...</tr><tbody><tr>...</tr></tbody></table>
You are worried about tables nested in tables, and so don't want to use an XPath like
table[#id="foo"]//tr.
If you could specify your desired XPath as a regex, it might look something like:
table[#id="foo"](/tbody)?/tr
In general, how can you specify an XPath expression that allows an optional element in the hierarchy of a selector?
To be clear, I'm not trying to solve a real-world problem or select a specific element of a specific document. I'm asking for techniques to solve a class of problems.
I don't see why you can't use this:
//table[#id='foo']/tr|//table[#id='foo']/tbody/tr
If you want one expression without node set union:
//tr[(.|parent::tbody)[1]/parent::table[#id='foo']]
In XPath 2.0, the optional step can be expressed as (tbody|.).
//table[#id="foo"]/(tbody|.)/tr
XPathTester.com demo
The pipe (|) denotes union (of two node-sets), the dot (.) denotes identity step (returning just what the previous step did).
This can be expanded to include more optional elements at once:
//table[#id="foo"]/(thead|tbody|tfoot|.)/tr
Use:
//table[#id="foo"]/*[self::tbody or self::thead or self::tfoot]/tr
|
//table[#id="foo"]/tr
Select any tr element that is a child of any table that has an id attribute "foo" or any tr element that is a child of a tbody that is a child any table.

how can I obtain a td with no value?

I have a table in which sometimes some records dont have a value
I am using these Xpath
//table/tbody/tr/td[not(td[string-length(normalize-space(text()))=0])]
//td[not(td[string-length(normalize-space(text()))=0])]
but it selects the whole table, how can I select only the td which are empty?
Thank you for all the help :)
Let's keep things simple. If you want to select tds without text try:
//table/tbody/tr/td[not(text())]
Demo
To complete, two alternatives to select empty td elements (the first one remove the useless parts of your XPath expression (normalize-space(), text(), and td[] inside the predicate) :
//td[string-length()=0]
//td[.=""]
The first XPath will look for td elements where the content length is equal to 0.
The second XPath will look for td elements which contain nothing.
But regarding your XPath tryouts, it seems you want to select td elements which are non-empty. If that's the case, just add a not inside the predicate :
//td[not(string-length()=0)]
//td[not(.="")]

import.io : Inserting an Independent row into result using XPATH

I am trying to scrape this site using import.io: ScoreCard
I am able to get the batting scores successfully but I want to insert additional column in the end which can tell me about the innings. So it should be relative to the name of batsman.
I tried to use XPATH: //*[#id="innings_1"]/div[1]/div/h4/b
but that will always return First Inning as ID is "innings_1".
Other IDs are innings_2/3/4 etc. Is there any way in XPATH where I can get this element relative to Batsman column?
Here is what I did in order to get the desired result:
I used following XPATH value.
.//a/ancestor::div/div[1]/div/h4/b
.//a was providing me name of Batsmen. I searched for its ancestors and the path div[1]/div/h4/b was being used by only Innings section.. So it did the trick :)
Try using starts-with():
//*[starts-with(#id,'innings_')/div/div/h4/b

Count attributes with certain value xPath

Currently i'm trying to count the total of items that are selected with xpath.
to count all items i can do:
count(/process_data/formData/xdp/datasets/data/Data//#selected)
but how can i count all items where the value of selected is true. (not knowing the previous node). If i knew the previous node i could do:
count(/process_data/formData/xdp/datasets/data/Data//node[#selected=true]/#selected)
but since i don't know this data, i can't use this. any ideas?
If you mean by not knowing the previous node that you want to check all nodes that may have a selected attribute I think you just have to change your XPath expression to:
count(/process_data/formData/xdp/datasets/data/Data//*[#selected='true'])
This assumes that selected is actually a string attribute.

better selenium xpath is expecting

I'm trying to create xpath expression which will work with selenium using following html snippet.
Below is table contains various row that gets incremented with uniquely generatedid(for example in following snippet that id is 1000).
Selenium has created following expressions when row of id 1000 was added in table. However instead of using id, I want to create xpath by using 3rd data element in row which is (MyName) in html snippet.
A possible suggestion is to not use xpath whenever possible.
http://saucelabs.com/blog/index.php/2011/05/why-css-locators-are-the-way-to-go-vs-xpath/
You need to convert the places in the XPATH where it is referring to the row by its ID to its relative position in the table.
In all of your XPATHs, you would change tr[#id='1000'] to tr[3]
Your first example XPATH would look liek this:
//tr[3]/td[1]/a[1]/img //tr[#id='1000']/td[1]/span/a/img
Your second example would follow similarly:
//tr[3]/td[1]/span/a/img
As would your third:
//tr[3]/td[1]/a[2]/img
Hopefully you are now able change the rest of them.

Resources