Page 1 of 1

Accessing two items on the same row

Posted: Sun Oct 20, 2013 5:07 pm
by richardgreene
Hi:

I am working with an application where I have no "hooks" to work with.

The only way I have to get to items is xpath.

My problem is, I need to access one column to find out it a value exists. If it does, I then need to go to the rightmost column and click on the corresponding image/button.

say ref = 24034

I am trying to make it so I can choose any value in the table and then be able to access the corresponding button/image.

I am having some issues with this.

Can you show me how you would do this?

Thanks...

I have uploaded a screen shot

Re: Accessing two items on the same row

Posted: Mon Oct 21, 2013 5:09 pm
by carsonw
There are a variety of ways you can go about this. Do you know what the reference number is in advance? In other words, do you know that you are looking for row data for ref 24034?

If so, then you can find that TD on the page... and go up one level to the TR and get all descendent TDs... that way you'll have all the data for that particular row (you can use a variable in the repository to refer to the reference number).

Assuming your column headers/order are always the same and exactly match the header row and data row... you will know that the first TD in the TR is the date.

We actually have a method that does this for us, but I'm not sure how well explaining it over the forum will work.

What we have is a header row in the repository, and a data row in the repository (with a locator value finding some unique value in the row - like the ref in the example above).

We then "find descendants or children accordingly to make a list of the headers and data cells, pass that to the function as well as the column name we want and then we get the data back.

It might be a little difficult to understand at first, but once you have it, and the method, it's a great way to pull data from a web table. The order of the columns doesn't matter because you go by column name and not index.

Below is a copy of the code, followed by an example how to use it:

Code: Select all

public static string GetDataByColumn<T>(IList<T> columnRow, IList<TdTag> dataRow, string columnName) where T : WebElement
		{
			try
			{
				string cellValue = null;
				List<T> columnHeaders = new List<T>(columnRow);
				int index = columnHeaders.FindIndex(element => element.InnerText != null && element.InnerText.Trim() == columnName);
				if (index != -1)
				{
					cellValue = dataRow[index].InnerText;
					
					// Check if cell contains nested elements and retrieve innertext if there is only one nested element
					List<Unknown> childElements = new List<Unknown>(dataRow[index].Children);
					if (string.IsNullOrEmpty(cellValue) || childElements.Count != 0)
					{
						if (childElements.Count == 1)
						{
							cellValue = childElements[0].As<WebElement>().InnerText;
						}
					}
				}
				
				if(string.IsNullOrEmpty(cellValue))
				{
					return cellValue;
				}
				else
				{
					return cellValue.Trim();
				}		
			}
			catch (Exception ex)
			{
				throw new InternalTestException("Failed to get get data by column name for column '" + columnName + "' due to the following error: " + ex.Message + ex.StackTrace);
			}
Then to use it:

Code: Select all

SSTRepository.Instance.locatorValue = orderNumberFromTest;
        	SSTRepositoryFolders.ApprovalAppFolder approvalObjects = SSTRepository.Instance.Approval;
        	
        	IList<TdTag> columnHeaders = approvalObjects.RowHeaderRow.FindChildren<TdTag>();
			IList<TdTag> dataCells = approvalObjects.RowDataRow.FindChildren<TdTag>();
			
			SSTPayments paymentFromApplication = new SSTPayments();						
			paymentFromApplication.OrderNumber = Utilities.GetDataByColumn(columnHeaders, dataCells, "Order Number");
			paymentFromApplication.AccountName = Utilities.GetDataByColumn(columnHeaders, dataCells, "Account");
			paymentFromApplication.TransactionType = Utilities.GetDataByColumn(columnHeaders, dataCells, "Transaction Type");
			paymentFromApplication.SettlementCurrency = Utilities.GetDataByColumn(columnHeaders, dataCells, "Currency");								
			paymentFromApplication.InitiatedDate = Convert.ToDateTime(Utilities.GetDataByColumn(columnHeaders, dataCells, "Initiated Date"));
			
			paymentTotal = Convert.ToDecimal(Utilities.GetDataByColumn(columnHeaders, dataCells, "Amount"));
			numberOfItemsFromApplication = Utilities.GetDataByColumn(columnHeaders, dataCells, "Number Items");
So you can see, but using Convert.ToDecimal(Utilities.GetDataByColumn(columnHeaders, dataCells, "Amount"));I can pull whatever value is in the "Amount" column by passing in my list of columnHeaders and dataCells along with the column name I'm want to look at (after setting my unique locator value).

This is great if you want everything in the entire row. If you only cared about an image you need to click, then you can create a repository entry for the image itself, and use the ref# as a locator variable in your repository.

I hope it's clear enough, again hard to explain over the forum.

Carson.

EDIT: I should add, this is how our data row looks like in the repository (basically we are saying find the cell that has this certain value in it, and then go up to the row, and give me that row back):

Code: Select all

.//td[@innertext=$locatorvalue]//..//tr
And the header row:

Code: Select all

.//td[@innertext~'Select']//..//tr
Depending on how "nicely" your webpage is coded will depend on how cleanly you can set up your repository. You can see that we have a variable in our data row ($locatorvalue), and we just put our orderId in there:

Code: Select all

SSTRepository.Instance.locatorValue = orderNumberFromTest;
then we have the entire row based on the order ID we're looking at. Note that our search values are pretty generic (just looking at the innertext of everything), but it's part of a rooted folder that narrows down the search considerably. You want to make your repository entry as narrow as possible to speed up finding the item. Hope that helps!

Re: Accessing two items on the same row

Posted: Tue Oct 22, 2013 10:03 pm
by richardgreene
Thanks for your reply Carsonw...very detailed...although I am still having trouble with this..I have tried using C# code but it does not work for this HTML items ...what has been working is something like this:

TableTag accountTable = "/dom[@domain='demo.united-ibank.com']//div[#'bodyDiv']/div[4]/div[3]/div[7]/table";


foreach (SpanTag row in accountTable.Find("./tbody/tr/?/td[5]/?/span"))
{

if (result1 == row.InnerText) //spantag found
{
Report.Info("row:" + row.InnerText);
}
}

//the above code gets the ref number...like 34033...but now I need to move over 2 more columns (column 7)
so I can click on the image/button. Here is where I am lost. I have tried sibling, and that does not work. If I try to a foreach to to find the td[7] it misses the spantag value (like 34033).

What I need is a way to find the spantag value which is going to be tr/td[5] span (like above), and then keeping the same tr move to td[7] and click();

As you can tell by this post, I am not familiar with what is available to me to make this happen.

Thanks again....Richard

Re: Accessing two items on the same row

Posted: Wed Oct 23, 2013 7:08 am
by Support Team
Hi Richard,

May I ask you to post or send (to [email protected]) a Ranorex snapshot file of this table?
The following link will show you how to generate a snapshot file: Creating Ranorex Snapshot Files.
The snapshot file will help us to analyze the structure of your table and to find a solution for you.

Regards,
Markus

Re: Accessing two items on the same row

Posted: Wed Oct 23, 2013 7:08 pm
by carsonw
richardgreene wrote:Thanks for your reply Carsonw...very detailed...although I am still having trouble with this..I have tried using C# code but it does not work for this HTML items ...what has been working is something like this:

TableTag accountTable = "/dom[@domain='demo.united-ibank.com']//div[#'bodyDiv']/div[4]/div[3]/div[7]/table";


foreach (SpanTag row in accountTable.Find("./tbody/tr/?/td[5]/?/span"))
{

if (result1 == row.InnerText) //spantag found
{
Report.Info("row:" + row.InnerText);
}
}

//the above code gets the ref number...like 34033...but now I need to move over 2 more columns (column 7)
so I can click on the image/button. Here is where I am lost. I have tried sibling, and that does not work. If I try to a foreach to to find the td[7] it misses the spantag value (like 34033).

What I need is a way to find the spantag value which is going to be tr/td[5] span (like above), and then keeping the same tr move to td[7] and click();

As you can tell by this post, I am not familiar with what is available to me to make this happen.

Thanks again....Richard
I can see why support is asking for a snapshot... is your table not made up of rows (TR) and cells (TDs) - this is how most web tables are constructed. The theory works like this (assuming you are using Table Rows, TR and table data (TD) or cells:

One you have the TD (the cell), you have to go "up" again to the row (TR) and then back "down" again to the new TD.

The trick is going up a level to the immediate parent row, and then right back down again.

So if you find your cell like this //table//tr//td[@innertext~'34003']
Then you want to go "up" one level to the row from there:
//table//tr//td[@innertext~'34003']//..//tr
And then you want to go back down again to the new data cell by somehow uniquely identifying the cell:
//table//tr//td[@innertext~'34003']//..//tr/td[7]
The above is the index, but maybe it's an image and it's the only image on the row, then you can identify it some other way (it's best to avoid using indexes if you can):
//table//tr//td[@innertext~'34003']//..//tr/td[@class='img']

And that would do it for you.

You don't even have to search the rows in a loop, you can literally put this in your repository and let Ranorex do it for you:

//table//tr//td[@innertext~$referenceNumber]

And then you just set the value of reference number, and it will find the row by itself, no loops needed.

You would have to adjust this with spans and so forth, but that's very hard to give an example with without knowing your structure (this is why support wants your snapshot).

Anyway, I hope that's useful to you :)

Re: Accessing two items on the same row

Posted: Fri Nov 28, 2014 12:06 pm
by emmetfb
carsonw wrote
The trick is going up a level to the immediate parent row, and then right back down again.

So if you find your cell like this //table//tr//td[@innertext~'34003']
Then you want to go "up" one level to the row from there:
//table//tr//td[@innertext~'34003']//..//tr
And then you want to go back down again to the new data cell by somehow uniquely identifying the cell:
//table//tr//td[@innertext~'34003']//..//tr/td[7]

And that would do it for you.
Many, many thanks.This has solved a long sought after solution to several of my issues. :D