使用 header 单元格文本定位 table 单元格
Locating table cell using the header cell text
我有 table 种外观,如下图所示,但不是单一的 table。 Header 在一个 table 中,行在另一个 table 中。
header 有一个 table 主要、语言和添加按钮,其余两行在另一个 table 中。现在我必须使用 header 文本来识别单元格。例如,如果我给出 1 Language
那么它必须找到选择阿拉伯语的第一行第二个单元格。同样,如果我给 2 Primary
它找到第二行第一列。
HTML代码如下图所示。如果可以解决这个问题,那么我会给出实际代码。
<div id="d78Pt30" style="width: 35em;" class="gridMaxHeight z-grid">
<div id="d78Pt30-head" class="z-grid-header" style="">
<table id="d78Pt30-headtbl" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-hdfaker">
<col id="d78Py30-hdfaker" style="width: 61px;">
<col id="d78Pz30-hdfaker" style="">
<col id="d78P_40-hdfaker" style="width: 50px;">
<col id="d78Px30-hdfaker-bar" style="width: 0px">
</colgroup>
<tbody id="d78Pt30-headrows">
<tr id="d78Px30" class="z-columns" style="text-align: left;">
<th id="d78Py30" class="z-column">
<div id="d78Py30-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78Py30-sort-icon"></i></div>
Primary
</div>
</th>
<th id="d78Pz30" class="z-column">
<div id="d78Pz30-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78Pz30-sort-icon"></i></div>
Language
</div>
</th>
<th id="d78P_40" class="z-column">
<div id="d78P_40-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78P_40-sort-icon"></i></div>
<a id="d78P040" class="z-a" href="javascript:;"><img src="assets/images/add.png"
align="absmiddle"></a></div>
</th>
<th id="d78Px30-bar" class="z-columns-bar"></th>
</tr>
</tbody>
</table>
</div>
<div class="z-grid-header-border"></div>
<div id="d78Pt30-body" class="z-grid-body" style="overflow: auto;">
<table id="d78Pt30-cave" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-bdfaker">
<col id="d78Py30-bdfaker" style="width: 61px;">
<col id="d78Pz30-bdfaker" style="">
<col id="d78P_40-bdfaker" style="width: 50px;">
</colgroup>
<tbody id="d78Pi50" class="z-rows">
<tr id="d78P260" class="gridMaxHeight z-row">
<td id="d78P360-chdextr" class="z-row-inner">
<div id="d78P360-cell" class="z-row-content"><span id="d78P360"
class="z-radio z-radio-default"><input
type="radio" id="d78P360-real" name="d78P360" checked="checked"><label for="d78P360-real"
id="d78P360-cnt"
class="z-radio-content"></label></span>
</div>
</td>
<td id="d78P460-chdextr" class="z-row-inner">
<div id="d78P460-cell" class="z-row-content"><span id="d78P460" class="z-combobox"
style="width: 225px;"><input id="d78P460-real"
class="z-combobox-input"
autocomplete="off"
value="" type="text"
size="20"
style="width: 196px;"><a
id="d78P460-btn" class="z-combobox-button"><i id="d78P460-icon"
class="z-combobox-icon z-icon-caret-down"></i></a><div
id="d78P460-pp" style="display: none;"></div></span></div>
</td>
<td id="d78Py60-chdextr" class="z-row-inner">
<div id="d78Py60-cell" class="z-row-content">
<div id="d78Py60" class="z-hlayout">
<div id="d78Pz60-chdex" class="z-hlayout-inner" style=""><a id="d78Pz60" class="z-a"
href="javascript:;"><img
src="assets/images/delete.png" align="absmiddle"></a></div>
</div>
</div>
</td>
</tr>
</tbody>
<tbody class="z-grid-emptybody">
<tr>
<td id="d78Pt30-empty" style="display: none;" colspan="3">
<div id="d78Pt30-empty-content" class="z-grid-emptybody-content">No data available</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
如您在 HTML 中所见,有两个 table,第一个包含 header,第二个包含其余行。
由于未提供 table 的完整标记,我在答案末尾使用 HTML 来说明可能的解决方案。
解决方案 1 - 对列索引进行硬编码
如果 table 列是 _static,最简单的解决方案是在您的代码中硬编码索引查找。此解决方案还可以更轻松地处理 header 没有文本的单元格 - 例如添加图标。
例如,您知道“语言”header 始终是列索引 1,而“主要”始终是列索引 0。因此,您知道如果需要数据行的“语言” , 它将是行中的第二个单元格。
def cell_by_header_text(browser, data_row_index, header_text)
columns = ['Primary', 'Language', 'Add'] # must match the order on the page
column_index = columns.index(header_text)
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
p cell_by_header_text(browser, 1, 'Language').html
#=> "<td><select><option selected=\"selected\">Arabic</option><option>Bengali</option></select></td>"
p cell_by_header_text(browser, 2, 'Primary').html
#=> "<td><input type=\"radio\" checked=\"\"></td>"
解决方案 2 - 列索引的动态查找
如果 table 列是 动态的 或者您想要更通用的解决方案,您可以从 header table.
def cell_by_header_text(browser, data_row_index, header_text)
header_table = browser.div(class: 'z-grid-header').table
column_index = header_table.tds.find_index { |td| td.text == header_text }
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
解决方案 3 - Domain-specific collection
如果你想提高可读性和灵活性,你可以更进一步,为网格创建一个domain-specific collection:
class LanguageRowCollection
include Enumerable
def initialize(browser)
@browser = browser
end
def each
data_rows.map { |data| yield LanguageRow.new(header_row, data) }
end
def [](value)
to_a[value]
end
private
def header_row
@browser.div(class: 'z-grid-header').table.tr
end
def data_rows
@browser.div(class: 'z-grid-body').table.trs
end
end
class LanguageRow
def initialize(header_row, tr)
@header_row = header_row
@tr = tr
end
def primary_cell
@tr.tds[@header_row.tds.map(&:text).index('Primary')]
end
def primary?
primary_cell.radio.selected?
end
def set_primary(value)
primary_cell.radio.set(value)
end
def language_cell
@tr.tds[@header_row.tds.map(&:text).index('Language')]
end
def language
language_cell.select.text
end
def set_language(value)
language_cell.select.set(value)
end
def remove_cell
# Locating the 3rd column by it's image since it doesn't have text
@tr.tds[@header_row.tds.find_index { |td| td.image(class: 'add').exists? }]
end
def remove
remove_cell.link.click
end
end
def languages(browser)
grid = browser.div(class: 'z-grid')
LanguageRowCollection.new(grid)
end
您可以获得 get/set 值的更易读的方式:
# Get/set the language of the first row (note the 0-based index)
languages(browser)[0].language
#=> "Arabic"
languages(browser)[0].set_language('Bengali')
您还可以根据值灵活地定位行:
# Get the primary language
languages(browser).find(&:primary?).language
#=> "Bengali"
# Remove the Arabic row
languages(browser).find { |l| l.language == 'Arabic' }.remove
HTML 例子
以下HTML用于上述示例。
<html>
<body>
<div id="d78Pt30" class="gridMaxHeight -grid">
<div class="z-grid-header">
<table>
<tr>
<td>Primary</td>
<td>Language</td>
<td>Add</td>
</tr>
</table>
</div>
<div class="z-grid-header-border"></div>
<div class="z-grid-body">
<table>
<tr>
<td><input type="radio"></td>
<td><select><option selected="selected">Arabic</option><option>Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
<tr>
<td><input type="radio" checked></td>
<td><select><option>Arabic</option><option selected="selected">Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
</div>
</div>
</body>
</html>
我有 table 种外观,如下图所示,但不是单一的 table。 Header 在一个 table 中,行在另一个 table 中。
header 有一个 table 主要、语言和添加按钮,其余两行在另一个 table 中。现在我必须使用 header 文本来识别单元格。例如,如果我给出 1 Language
那么它必须找到选择阿拉伯语的第一行第二个单元格。同样,如果我给 2 Primary
它找到第二行第一列。
HTML代码如下图所示。如果可以解决这个问题,那么我会给出实际代码。
<div id="d78Pt30" style="width: 35em;" class="gridMaxHeight z-grid">
<div id="d78Pt30-head" class="z-grid-header" style="">
<table id="d78Pt30-headtbl" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-hdfaker">
<col id="d78Py30-hdfaker" style="width: 61px;">
<col id="d78Pz30-hdfaker" style="">
<col id="d78P_40-hdfaker" style="width: 50px;">
<col id="d78Px30-hdfaker-bar" style="width: 0px">
</colgroup>
<tbody id="d78Pt30-headrows">
<tr id="d78Px30" class="z-columns" style="text-align: left;">
<th id="d78Py30" class="z-column">
<div id="d78Py30-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78Py30-sort-icon"></i></div>
Primary
</div>
</th>
<th id="d78Pz30" class="z-column">
<div id="d78Pz30-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78Pz30-sort-icon"></i></div>
Language
</div>
</th>
<th id="d78P_40" class="z-column">
<div id="d78P_40-cave" class="z-column-content">
<div class="z-column-sorticon"><i id="d78P_40-sort-icon"></i></div>
<a id="d78P040" class="z-a" href="javascript:;"><img src="assets/images/add.png"
align="absmiddle"></a></div>
</th>
<th id="d78Px30-bar" class="z-columns-bar"></th>
</tr>
</tbody>
</table>
</div>
<div class="z-grid-header-border"></div>
<div id="d78Pt30-body" class="z-grid-body" style="overflow: auto;">
<table id="d78Pt30-cave" style="table-layout: fixed;" width="100%">
<colgroup id="d78Px30-bdfaker">
<col id="d78Py30-bdfaker" style="width: 61px;">
<col id="d78Pz30-bdfaker" style="">
<col id="d78P_40-bdfaker" style="width: 50px;">
</colgroup>
<tbody id="d78Pi50" class="z-rows">
<tr id="d78P260" class="gridMaxHeight z-row">
<td id="d78P360-chdextr" class="z-row-inner">
<div id="d78P360-cell" class="z-row-content"><span id="d78P360"
class="z-radio z-radio-default"><input
type="radio" id="d78P360-real" name="d78P360" checked="checked"><label for="d78P360-real"
id="d78P360-cnt"
class="z-radio-content"></label></span>
</div>
</td>
<td id="d78P460-chdextr" class="z-row-inner">
<div id="d78P460-cell" class="z-row-content"><span id="d78P460" class="z-combobox"
style="width: 225px;"><input id="d78P460-real"
class="z-combobox-input"
autocomplete="off"
value="" type="text"
size="20"
style="width: 196px;"><a
id="d78P460-btn" class="z-combobox-button"><i id="d78P460-icon"
class="z-combobox-icon z-icon-caret-down"></i></a><div
id="d78P460-pp" style="display: none;"></div></span></div>
</td>
<td id="d78Py60-chdextr" class="z-row-inner">
<div id="d78Py60-cell" class="z-row-content">
<div id="d78Py60" class="z-hlayout">
<div id="d78Pz60-chdex" class="z-hlayout-inner" style=""><a id="d78Pz60" class="z-a"
href="javascript:;"><img
src="assets/images/delete.png" align="absmiddle"></a></div>
</div>
</div>
</td>
</tr>
</tbody>
<tbody class="z-grid-emptybody">
<tr>
<td id="d78Pt30-empty" style="display: none;" colspan="3">
<div id="d78Pt30-empty-content" class="z-grid-emptybody-content">No data available</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
如您在 HTML 中所见,有两个 table,第一个包含 header,第二个包含其余行。
由于未提供 table 的完整标记,我在答案末尾使用 HTML 来说明可能的解决方案。
解决方案 1 - 对列索引进行硬编码
如果 table 列是 _static,最简单的解决方案是在您的代码中硬编码索引查找。此解决方案还可以更轻松地处理 header 没有文本的单元格 - 例如添加图标。
例如,您知道“语言”header 始终是列索引 1,而“主要”始终是列索引 0。因此,您知道如果需要数据行的“语言” , 它将是行中的第二个单元格。
def cell_by_header_text(browser, data_row_index, header_text)
columns = ['Primary', 'Language', 'Add'] # must match the order on the page
column_index = columns.index(header_text)
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
p cell_by_header_text(browser, 1, 'Language').html
#=> "<td><select><option selected=\"selected\">Arabic</option><option>Bengali</option></select></td>"
p cell_by_header_text(browser, 2, 'Primary').html
#=> "<td><input type=\"radio\" checked=\"\"></td>"
解决方案 2 - 列索引的动态查找
如果 table 列是 动态的 或者您想要更通用的解决方案,您可以从 header table.
def cell_by_header_text(browser, data_row_index, header_text)
header_table = browser.div(class: 'z-grid-header').table
column_index = header_table.tds.find_index { |td| td.text == header_text }
data_table = browser.div(class: 'z-grid-body').table
data_table[data_row_index - 1][column_index] # returns Watir::Cell
end
解决方案 3 - Domain-specific collection
如果你想提高可读性和灵活性,你可以更进一步,为网格创建一个domain-specific collection:
class LanguageRowCollection
include Enumerable
def initialize(browser)
@browser = browser
end
def each
data_rows.map { |data| yield LanguageRow.new(header_row, data) }
end
def [](value)
to_a[value]
end
private
def header_row
@browser.div(class: 'z-grid-header').table.tr
end
def data_rows
@browser.div(class: 'z-grid-body').table.trs
end
end
class LanguageRow
def initialize(header_row, tr)
@header_row = header_row
@tr = tr
end
def primary_cell
@tr.tds[@header_row.tds.map(&:text).index('Primary')]
end
def primary?
primary_cell.radio.selected?
end
def set_primary(value)
primary_cell.radio.set(value)
end
def language_cell
@tr.tds[@header_row.tds.map(&:text).index('Language')]
end
def language
language_cell.select.text
end
def set_language(value)
language_cell.select.set(value)
end
def remove_cell
# Locating the 3rd column by it's image since it doesn't have text
@tr.tds[@header_row.tds.find_index { |td| td.image(class: 'add').exists? }]
end
def remove
remove_cell.link.click
end
end
def languages(browser)
grid = browser.div(class: 'z-grid')
LanguageRowCollection.new(grid)
end
您可以获得 get/set 值的更易读的方式:
# Get/set the language of the first row (note the 0-based index)
languages(browser)[0].language
#=> "Arabic"
languages(browser)[0].set_language('Bengali')
您还可以根据值灵活地定位行:
# Get the primary language
languages(browser).find(&:primary?).language
#=> "Bengali"
# Remove the Arabic row
languages(browser).find { |l| l.language == 'Arabic' }.remove
HTML 例子
以下HTML用于上述示例。
<html>
<body>
<div id="d78Pt30" class="gridMaxHeight -grid">
<div class="z-grid-header">
<table>
<tr>
<td>Primary</td>
<td>Language</td>
<td>Add</td>
</tr>
</table>
</div>
<div class="z-grid-header-border"></div>
<div class="z-grid-body">
<table>
<tr>
<td><input type="radio"></td>
<td><select><option selected="selected">Arabic</option><option>Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
<tr>
<td><input type="radio" checked></td>
<td><select><option>Arabic</option><option selected="selected">Bengali</option></select></td>
<td><a href="#">Minus</a></td>
</tr>
</div>
</div>
</body>
</html>