nhrcpt
nhrcpt

Reputation: 872

How to construct a XPath to include specific elements from an HTML?

I have a table and I want only to select the buttons on that table. As we can see, there are only 4 buttons on this table:

enter image description here

I have created the following Xpath to filter out these 4 buttons, and no other button on the page:

//*[@id="studentListTable"]/thead/tr/th[contains(., "Actions")]//following::button  | //*[@id="studentListTable_info"]//preceding::button 

But this is not working.
This XPath is actually locating all the buttons on the page irrespective of the buttons location.

What is wrong here?

How can I fix it so that only the four buttons are located by this expression?

The HTML snippet :

<div _ngcontent-c7="" appcard="" class="card">
    <div _ngcontent-c7="" class="card-header">
        <h5 _ngcontent-c7="">Student list <!----></h5></div>
    <ul _ngcontent-c7="" class="card-actions">
        <li _ngcontent-c7="">
            <button _ngcontent-c7="" appcardfullscreen="" class="card-action">
                <i _ngcontent-c7="" class="fa fa-arrows-alt"></i></button></li>
        <li _ngcontent-c7="">
            <button _ngcontent-c7="" appcardcollapse="" class="card-action icon-collapse"><i _ngcontent-c7="" class="material-icons">expand_more</i></button></li></ul>
    <!---->
    <div _ngcontent-c7="" class="card-body">
        <div id="studentListTable_wrapper" class="dataTables_wrapper no-footer">
            <div class="dataTables_length" id="studentListTable_length">
                <label>Show <select name="studentListTable_length" aria-controls="studentListTable" class="">
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option><option value="100">100</option>
                </select> entries</label></div>
            <div id="studentListTable_filter" class="dataTables_filter">
                <label>Search:<input type="search" class="" placeholder="" aria-controls="studentListTable"></label>
            </div>
            <table _ngcontent-c7="" class="table table-striped dataTable no-footer" datatable="" id="studentListTable" role="grid" aria-describedby="studentListTable_info">
            <thead _ngcontent-c7="">
            <tr _ngcontent-c7="" role="row">
                <th _ngcontent-c7="" class="sorting_asc" tabindex="0" aria-controls="studentListTable" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Student ID: activate to sort column descending" style="width: 101px;">Student ID</th>
                 <th _ngcontent-c7="" class="sorting_disabled" rowspan="1" colspan="1" aria-label="Actions" style="width: 106px;">Actions</th></tr>
            </thead><!----><tbody _ngcontent-c7=""><!---->
            <tr _ngcontent-c7="" role="row" class="odd">
                <td _ngcontent-c7="" class="sorting_1">123456</td>
                 <td _ngcontent-c7="">
                    <a href="unsafe:javascript:void(0)">
                        <i class="material-icons text-warning">info</i> Not Started</a></td>
                <td _ngcontent-c7="">Null</td>
                <td _ngcontent-c7="" class="text-left"><!----><div _ngcontent-c7="">
                    <button _ngcontent-c7="" class="btn btn-sm btn-sm-action mr-2 btn-outline-info" container="body" placement="left" popoverclass="btn-popover" triggers="mouseenter:mouseleave" type="button" tabindex="0">
                        <i _ngcontent-c7="" class="fa fa-arrow-right"></i></button></div><!----><!----><!----></td></tr>
            <tr _ngcontent-c7="" role="row" class="even">
                <td _ngcontent-c7="" class="sorting_1">153246</td>
                 <td _ngcontent-c7=""><a href="unsafe:javascript:void(0)"><i class="fa fa-unlock mr-2"></i>In Progress</a></td>
                <td _ngcontent-c7="">Herndon MS</td>
                <td _ngcontent-c7="" class="text-left"><!----><!----><div _ngcontent-c7=""><!----><div _ngcontent-c7="" class="d-flex align-items-center">
                    <button _ngcontent-c7="" class="btn btn-sm btn-sm-action mr-2 btn-outline-info col" container="body" placement="left" popoverclass="btn-popover" triggers="mouseenter:mouseleave" type="button" tabindex="0">
                        <i _ngcontent-c7="" class="fa fa-pencil"></i></button>
                    <button _ngcontent-c7="" class="btn btn-sm btn-sm-action mr-2 btn-outline-danger col" container="body" placement="left" popoverclass="btn-popover" triggers="mouseenter:mouseleave" type="button">
                        <i _ngcontent-c7="" class="fa fa-trash-o"></i></button></div><!----></div><!----><!----></td></tr>
            <tr _ngcontent-c7="" role="row" class="odd">
                <td _ngcontent-c7="" class="sorting_1">234135</td>
                 <td _ngcontent-c7="" class="text-left"><!----><!----><!---->
                    <div _ngcontent-c7="">
                        <button _ngcontent-c7="" class="btn btn-sm btn-sm-action mr-2 btn-outline-info" container="body" placement="left" popoverclass="btn-popover" triggers="mouseenter:mouseleave" type="button" tabindex="0">
                            <i _ngcontent-c7="" class="fa fa-eye"></i></button></div><!----></td></tr></tbody><!----><!----><!----></table>
            <div class="dataTables_info" id="studentListTable_info" role="status" aria-live="polite">Showing 1 to 3 of 3 entries</div>
            <div class="dataTables_paginate paging_simple_numbers" id="studentListTable_paginate">
                <a class="paginate_button previous disabled" aria-controls="studentListTable" data-dt-idx="0" tabindex="0" id="studentListTable_previous">Previous</a>
                <span>
                    <a class="paginate_button current" aria-controls="studentListTable" data-dt-idx="1" tabindex="0">1</a>
                </span>
                <a class="paginate_button next disabled" aria-controls="studentListTable" data-dt-idx="2" tabindex="0" id="studentListTable_next">Next</a></div></div></div></div>

Upvotes: 1

Views: 855

Answers (6)

user10996264
user10996264

Reputation:

You can select buttons by Student Id using below xpath as example with 153246 id:

//table[@id='studentListTable']//tr[@role='row' and ./td[@class='sorting_1' and .='153246']]//button

Upvotes: 0

JeffC
JeffC

Reputation: 25611

The BUTTONs you want are the only buttons inside the table and the table has an ID, studentListTable, so all you need are the children BUTTONs of the ID.

From the HTML you have provided, something simple like the below will work.

XPath

//[@id='studentListTable']//button

CSS selector

#studentListTable button

Upvotes: 0

undetected Selenium
undetected Selenium

Reputation: 193108

A few points:

  • The buttons in the first and third row are within class="odd"
  • The two buttons in the second row are within class="even"

To filter out these 4 buttons you can use the following XPath based solution:

"//table[@class='table table-striped dataTable no-footer' and @id='studentListTable']//tbody//tr[@class= 'odd' or @class='even']//td[@class='text-left']//button"

A snapshot of the matching result through xpath checker:

matching_xpath

Note: You havn't mentioned the language binding you are using so as the elements are Angular elements to locate the element you have to induce WebDriverWait for the element to be clickable.

Upvotes: 2

har07
har07

Reputation: 89285

If I understand this correctly, the title means you want combine the 2 attempted XPath expressions to get buttons that is located after th containing text "Actions" and before div with id "studentListTable_info" :

//*[@id="studentListTable"]/thead/tr/th[contains(., "Actions")]//following::button[
    following::*[@id="studentListTable_info"]
]

Upvotes: 0

catch32
catch32

Reputation: 18582

  1. Difficult to answer your first question what is wrong there.
    You are using some | and two different ids and maybe it isn't fully correct.
    And you used thead element in your Xpath. Despite the fact that all buttons located at tbody. Anyway, your locator gets all HTML buttons from that page.

  2. I tried to modify Xpath to following:

//table//button

And it worked well:

enter image description here

However, it isn't very good Xpath.
So try to bind it to some nearest id. After update it can be like:

//div[@id='studentListTable_wrapper']//table//button

The result of the evaluation is the same.

And much more redundant version will be (not recomended to use, just for example reason):

//div[@id='studentListTable_wrapper']//table/tbody/tr/td/div//button

BTW to my opinion much better is to use locators like:

//div[@id='...']

instead of:

//*[...]

Difficult to see if it can be the reason of incorrect select.
For sure it is much more readable and easier to understand in the future support.

Upvotes: 2

zx485
zx485

Reputation: 29022

You can use the following XPath-1.0 expression:

//table[@id="studentListTable" and thead/tr/th/text() =  "Actions"]/tbody/tr/td[@class="sorting_1"]

to select the following three items:

<td _ngcontent-c7="" class="sorting_1">123456</td>
<td _ngcontent-c7="" class="sorting_1">153246</td>
<td _ngcontent-c7="" class="sorting_1">234135</td>

To proceed further to get the four buttons contained in these three tables, the following XPath will do:

//table[@id="studentListTable" and thead/tr/th/text() =  "Actions"]/tbody/tr/td[@class="sorting_1"]/../../tr/td//button

Its result consists of the following four items:

<button ... type="button" tabindex="0">
    <i _ngcontent-c7="" class="fa fa-arrow-right"/>
</button>
<button ... type="button" tabindex="0">
    <i _ngcontent-c7="" class="fa fa-pencil"/>
</button>
<button ... type="button">
    <i _ngcontent-c7="" class="fa fa-trash-o"/>
</button>
<button ... type="button" tabindex="0">
    <i _ngcontent-c7="" class="fa fa-eye"/>
</button>

Upvotes: 2

Related Questions