Tellurium Tutorial Series: the List object

2 views
Skip to first unread message

John.Ji...@gmail.com

unread,
Nov 20, 2008, 12:06:23 AM11/20/08
to tellurium-users
List object is similar to the Table object. It has three features:
1) It is a Container type object to hold UI elements
2) It can hold variable number of UI elements and you can use index to
refer to the specific UI element
3) You can use templates to define UI elements.

For example,

ui.List(uid: "example", clocator: [whatever_attributes]){
TextBox(uid: "1", clocator: [whatever_attributes])
UrlLink(uid: "all", clocator: [whatever_attributes])
}

That is to say, the List's first UI element is a TextBox and the rest
are UrlLinks. The rule to apply templates is "apply the specific
template first and the general template later". In the above example,
for the
first UI element, we first look at if we have the template on position
1. Since the template is defined, we use it.

For the second UI element, there is no specific template defined, thus
the general template for "all" will be used. As a result, the second
UI element is a UrlLink.

List has a special attribute "separator", which is used to separate
different UI elements. For instance,
look at the following html source,

<ul class="a">
<li>
<A HREF="site?tcid=a"
class="b">AA
</A>
</li>
<li>
<A HREF="site?tcid=b"
class="b">BB
</A>
</li>
<li>
<A HREF="site?;tcid=c"
class="b">CC
</A>
</li>
<li>
<A HREF="site?tcid=d"
class="b">DD
</A>
</li>
</ul>

Obviously, the separator is the tag "li", thus, the UI module is
described as follows,

ui.List(uid: "list", clocator: [tag: "ul", class: "a"], separator:
"li"){
UrlLink(uid: "all", clocator: [class: "b"])
}

Once the separator is defined, it is very easy to locate the UI
element by its index, for instance,
"list[3]" will refer to the following XPath "//ul[@class="a"]/li[3]/
a", where the separator
"li" is used to identify different UI elements, i.e., "/" + separator
+ "[${index}]"

What if there is no clear html representation as above and we do not
have the separator
defined such as the following html source,

<div id="test">
<table id="id3:id7">
<tbody>
<tr>
<td>
<a href="javascript:void(0);">My Label 1</a>
</td>
</tr>
</tbody>
</table>
<div>good</div>
<table id="id3:id8">
<tbody>
<tr>
<td>
<a href="javascript:void(0);">My Label 2</a>
</td>
</tr>
</tbody>
</table>
<input title="cool"/>
<table id="id4:id9">
<tbody>
<tr>
<td>
<a href="javascript:void(0);">My Label 3</a>
</td>
</tr>
</tbody>
</table>
</div>

If we like to use List for the above HTML source, the UI module could
be

ui.List(uid: "list", clocator: [tag: "div", id: "test"]){
TextBox(uid: "2", clocator: [tag: "div"])
InputBox(uid: "4", clocator: [title: "cool"])
Table(uid: "all", clocator: [:]){
UrlLink(uid: "row: 1, column: 1", clocator: [:])
}
}

You may wonder how the actual runtime XPath is generated from it with
out the separator.
The mystery is the templates. For example,

For "list[1]", Tellurium will first look at the template for position
1, since none is defined,
use the general template, the table, that is to say,

For "List[1]", the procedure is: table[1], and the current XPath is
"//div[@id='text']/table[1]".

For "List[2]", the procedure is: table[1] -> div[1], XPath is "//div
[@id='text']/div[1]".

For "List[3]", the procedure is: table[1] -> div[1] -> table[2], XPath
is "//div[@id='text']/table[2]"

For "List[4]", the procedure is: table[1] -> div[1] -> table[2] ->
input[1], XPath is "//div[@id='text']/input[1]"

For "List[5]", the procedure is: table[1] -> div[1] -> table[2] ->
input[1] -> table[3], XPath is "//div[@id='text']/table[3]"

From above observation, the algorithm is simple:

"For the i-th element, start from index 1, count the occurrence of a
tag for each template used and also the last tag used. The XPath is "/
descendant::${lastTag}[${lastOccur}]".

The detailed algorithm is shown as follows,

protected String deriveListLocator(int index) {
Map<String, Integer> tags = new HashMap<String, Integer>()
UiObject last = null
for (int i = 1; i <= index; i++) {
//findUiObject is used to search for the template for the
UI element on the specific index
UiObject obj = findUiObject(i)
String tag = obj.locator.getTag()
Integer occur = tags.get(tag)
if (occur == null) {
tags.put(tag, 1)
} else {
tags.put(tag, occur + 1)
}
if (i == index) {
last = obj
}
}

String lastTag = last.locator.getTag()
Integer lastOccur = tags.get(lastTag)

return "/descendant::${lastTag}[${lastOccur}]"
}
Reply all
Reply to author
Forward
0 new messages