Atata - 无法从 table 行中找到元素
Atata - Unable to locate elements from table rows
目前我正在努力从 table 行中找到一个元素:
我正在尝试通过以下方式找到它:
detailPage.Users.Rows[x => x.Project == "Unassigned"].Project.Should.Equal("Unassigned");
我收到此错误:
Atata.AssertionException: '无效 "Users" table 的“项目==
"Unassigned"" 行的 "Project" 元素内容。
预期:应该等于 "Unassigned"
实际:空
This is the full table HTML:
<table class="table table-bordered table-hover table-responsive" id="js-fixed-table">
<thead class="header-static" style="opacity: 1;">
<tr>
<th class="text-center vertical-align-middle column-fixed" rowspan="2" style="left: 0px; background: none;">Name</th>
<th class="text-center vertical-align-middle" rowspan="2">E-mail</th>
<th class="text-center vertical-align-middle" rowspan="2">Start date</th>
<th class="text-center vertical-align-middle" rowspan="2">Location</th>
<th class="text-center vertical-align-middle" rowspan="2">City</th>
<th class="text-center vertical-align-middle" rowspan="2">Company</th>
<th class="text-center vertical-align-middle" rowspan="2">Work Category</th>
<th class="text-center vertical-align-middle" rowspan="2">Position</th>
<th class="text-center vertical-align-middle" rowspan="2">Expertise Level</th>
<th class="text-center vertical-align-middle" rowspan="2">Client</th>
<th class="text-center vertical-align-middle" rowspan="2">Project</th>
<th class="text-center vertical-align-middle" rowspan="2">Project work (paid)</th>
<th class="text-center vertical-align-middle" rowspan="2">Project work (unpaid)</th>
<th class="text-center vertical-align-middle" rowspan="2">Overtime</th>
<th class="text-center vertical-align-middle" rowspan="2">Holiday Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Paid time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Unpaid time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Sick leave</th>
<th class="text-center vertical-align-middle" rowspan="2">Business trip</th>
<th class="text-center vertical-align-middle" rowspan="2">Special time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Paid time off (paid by client)</th>
<th class="text-center vertical-align-middle" rowspan="2">Total</th>
<th class="text-center vertical-align-middle" rowspan="2">Official Company Working Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Available Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Availability</th>
<th class="text-center vertical-align-middle" rowspan="2">Billable Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Billability</th>
<th class="text-center vertical-align-middle" rowspan="2">Rate (original currency)</th>
<th class="text-center vertical-align-middle" rowspan="2">Currency</th>
<th class="text-center vertical-align-middle" rowspan="2">Exchange Rate</th>
<th class="text-center vertical-align-middle" rowspan="2">Revenue (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Revenue Total (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Weighted AR (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Net Salary (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Total Employee Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Additional Remuneration (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Direct Project Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Direct Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Gross Margin (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Gross Margin Percent (BGN)</th>
</tr>
</thead>
<tbody><tr style="color:" title="" class="missing-rate-row">
<td data-toggle="modal" data-target="#user-details-modal" data-id="160" class="vertical-align-middle cursor-pointer column-fixed" rowspan="2" style="left: 0px; background: none;">
Ivan Garlanov
</td>
<td class="vertical-align-middle" rowspan="2">kjfwoi231@yahoo.com</td>
<td class="vertical-align-middle" rowspan="2">2016-07-07</td>
<td class="vertical-align-middle" rowspan="2">Nikola Tesla</td>
<td class="vertical-align-middle" rowspan="2">Nis</td>
<td class="vertical-align-middle" rowspan="2">OneStar</td>
<td class="vertical-align-middle" rowspan="2">Direct</td>
<td class="vertical-align-middle" rowspan="2">Admin Operations</td>
<td class="vertical-align-middle" rowspan="2">Architect</td>
<td class="vertical-align-middle">PrismaSoft</td>
<td class="vertical-align-middle">BioFruit</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">0</td>
<td class="vertical-align-middle text-right">0</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
8
</td>
<td class="vertical-align-middle text-right" rowspan="2">32.00</td>
<td class="vertical-align-middle text-right" rowspan="2">176</td>
<td class="vertical-align-middle text-right" rowspan="2">24.00</td>
<td class="vertical-align-middle text-right" rowspan="2">0.14</td>
<td class="vertical-align-middle text-right" rowspan="2">16.00</td>
<td class="vertical-align-middle text-right" rowspan="2">66.67%</td>
<td class="vertical-align-middle text-right">112.56</td>
<td class="vertical-align-middle">EUR</td>
<td class="vertical-align-middle text-right">1.95583</td>
<td class="vertical-align-middle text-right">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="2">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="2">220.14</td>
<td class="vertical-align-middle text-right" rowspan="2">1600.00</td>
<td class="vertical-align-middle text-right" rowspan="2">2057.89</td>
<td class="vertical-align-middle text-right" rowspan="2">200.00</td>
<td class="vertical-align-middle text-right">1693.42</td>
<td class="vertical-align-middle text-right" rowspan="2">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="2">1264.34</td>
<td class="vertical-align-middle text-right" rowspan="2">0.36</td>
</tr>
<tr style="color:" title="" class="missing-rate-row">
<td class="vertical-align-middle">Unassigned</td>
<td class="vertical-align-middle">Unassigned</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0.00
</td>
<td class="vertical-align-middle">
BGN
</td>
<td class="vertical-align-middle text-right">
1.00000
</td>
<td class="vertical-align-middle text-right">
</td>
<td class="vertical-align-middle text-right">
564.47
</td>
</tr>
<tr style="color:" title="" class="missing-rate-row">
<td class="vertical-align-middle column-fixed" rowspan="1" style="left: 0px; background: none;">
Total
</td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">0</td>
<td class="vertical-align-middle text-right">0</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
8
</td>
<td class="vertical-align-middle text-right" rowspan="1">32.00</td>
<td class="vertical-align-middle text-right" rowspan="1">176</td>
<td class="vertical-align-middle text-right" rowspan="1">24.00</td>
<td class="vertical-align-middle text-right" rowspan="1">0.14</td>
<td class="vertical-align-middle text-right" rowspan="1">16.00</td>
<td class="vertical-align-middle text-right" rowspan="1">66.67%</td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle text-right" rowspan="1">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="1">220.14</td>
<td class="vertical-align-middle text-right" rowspan="1">1600.00</td>
<td class="vertical-align-middle text-right" rowspan="1">2057.89</td>
<td class="vertical-align-middle text-right" rowspan="1">200.00</td>
<td class="vertical-align-middle text-right">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="1">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="1">1264.34</td>
<td class="vertical-align-middle text-right" rowspan="1">0.36</td>
</tr>
</tbody></table>
table 单元格查找 FindByColumnHeaderAttribute
和 FindByColumnIndexAttribute
的标准 Atata 属性不适用于此类 table,因为行具有不同数量的 <td>
单元格元素因为 rowspan
.
我在 atata-samples
存储库中创建了单独的示例项目 https://github.com/atata-framework/atata-samples/tree/master/TableWithRowSpannedCells 来试验此类 table 并提供解决方案。我最终为您的 table 提供了 3 种方法。因此,请按照 link 查看有关它们的来源和详细信息。
这是使用 XPath 查找的第一种直接方法:
using Atata;
namespace AtataSamples.TableWithRowSpannedCells
{
using _ = TableUsingXPathPage;
[Url("table-with-row-spanned-cells")]
public class TableUsingXPathPage : Page<_>
{
public Table<UserRow, _> Users { get; private set; }
public class UserRow : TableRow<_>
{
[FindByXPath(XPathTo.RowSpannedCell, Index = 0)]
public Text<_> Name { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 2)]
[Format("yyyy-MM-dd")]
public Date<_> StartDate { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 8)]
public Text<_> ExpertiseLevel { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 0)]
public Text<_> Client { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 1)]
public Text<_> Project { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 16)]
public Number<_> DirectProjectCost { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 22)]
public Number<_> GrossMarginPercent { get; private set; }
private static class XPathTo
{
public const string RowSpannedCell = "(self::*[td[@rowspan]] | preceding-sibling::tr[td[@rowspan]])[last()]/td[@rowspan]";
public const string NonRowSpannedCell = "td[not(@rowspan)]";
}
}
}
}
我们的想法是检测和拆分两种类型的 <td>
单元格元素:有和没有 rowspan
属性。
- 可以在
<tr>
的范围内找到没有 rowspan
的单元格:"td[not(@rowspan)]"
(请注意,这是将针对特定 <tr>
执行的相对 XPath)
- 带有
rowspan
的单元格在 tr
中可能会丢失,在这种情况下,您需要在最近的包含 rowspan
的前一个兄弟 <tr>
中找到此单元格:"(self::*[td[@rowspan]] | preceding-sibling::tr[td[@rowspan]])[last()]/td[@rowspan]"
因此,您可以根据单元格的类型使用其中一个 XPath 来查找单元格,并在相同类型的行的范围内指定它的索引。
查看 Table with Row-Spanned Cells 示例以了解其他方法和详细信息。
目前我正在努力从 table 行中找到一个元素:
我正在尝试通过以下方式找到它:
detailPage.Users.Rows[x => x.Project == "Unassigned"].Project.Should.Equal("Unassigned");
我收到此错误:
Atata.AssertionException: '无效 "Users" table 的“项目== "Unassigned"" 行的 "Project" 元素内容。 预期:应该等于 "Unassigned" 实际:空
This is the full table HTML:
<table class="table table-bordered table-hover table-responsive" id="js-fixed-table">
<thead class="header-static" style="opacity: 1;">
<tr>
<th class="text-center vertical-align-middle column-fixed" rowspan="2" style="left: 0px; background: none;">Name</th>
<th class="text-center vertical-align-middle" rowspan="2">E-mail</th>
<th class="text-center vertical-align-middle" rowspan="2">Start date</th>
<th class="text-center vertical-align-middle" rowspan="2">Location</th>
<th class="text-center vertical-align-middle" rowspan="2">City</th>
<th class="text-center vertical-align-middle" rowspan="2">Company</th>
<th class="text-center vertical-align-middle" rowspan="2">Work Category</th>
<th class="text-center vertical-align-middle" rowspan="2">Position</th>
<th class="text-center vertical-align-middle" rowspan="2">Expertise Level</th>
<th class="text-center vertical-align-middle" rowspan="2">Client</th>
<th class="text-center vertical-align-middle" rowspan="2">Project</th>
<th class="text-center vertical-align-middle" rowspan="2">Project work (paid)</th>
<th class="text-center vertical-align-middle" rowspan="2">Project work (unpaid)</th>
<th class="text-center vertical-align-middle" rowspan="2">Overtime</th>
<th class="text-center vertical-align-middle" rowspan="2">Holiday Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Paid time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Unpaid time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Sick leave</th>
<th class="text-center vertical-align-middle" rowspan="2">Business trip</th>
<th class="text-center vertical-align-middle" rowspan="2">Special time off</th>
<th class="text-center vertical-align-middle" rowspan="2">Paid time off (paid by client)</th>
<th class="text-center vertical-align-middle" rowspan="2">Total</th>
<th class="text-center vertical-align-middle" rowspan="2">Official Company Working Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Available Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Availability</th>
<th class="text-center vertical-align-middle" rowspan="2">Billable Hours</th>
<th class="text-center vertical-align-middle" rowspan="2">Billability</th>
<th class="text-center vertical-align-middle" rowspan="2">Rate (original currency)</th>
<th class="text-center vertical-align-middle" rowspan="2">Currency</th>
<th class="text-center vertical-align-middle" rowspan="2">Exchange Rate</th>
<th class="text-center vertical-align-middle" rowspan="2">Revenue (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Revenue Total (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Weighted AR (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Net Salary (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Total Employee Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Additional Remuneration (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Direct Project Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Direct Cost (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Gross Margin (BGN)</th>
<th class="text-center vertical-align-middle" rowspan="2">Gross Margin Percent (BGN)</th>
</tr>
</thead>
<tbody><tr style="color:" title="" class="missing-rate-row">
<td data-toggle="modal" data-target="#user-details-modal" data-id="160" class="vertical-align-middle cursor-pointer column-fixed" rowspan="2" style="left: 0px; background: none;">
Ivan Garlanov
</td>
<td class="vertical-align-middle" rowspan="2">kjfwoi231@yahoo.com</td>
<td class="vertical-align-middle" rowspan="2">2016-07-07</td>
<td class="vertical-align-middle" rowspan="2">Nikola Tesla</td>
<td class="vertical-align-middle" rowspan="2">Nis</td>
<td class="vertical-align-middle" rowspan="2">OneStar</td>
<td class="vertical-align-middle" rowspan="2">Direct</td>
<td class="vertical-align-middle" rowspan="2">Admin Operations</td>
<td class="vertical-align-middle" rowspan="2">Architect</td>
<td class="vertical-align-middle">PrismaSoft</td>
<td class="vertical-align-middle">BioFruit</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">0</td>
<td class="vertical-align-middle text-right">0</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
8
</td>
<td class="vertical-align-middle text-right" rowspan="2">32.00</td>
<td class="vertical-align-middle text-right" rowspan="2">176</td>
<td class="vertical-align-middle text-right" rowspan="2">24.00</td>
<td class="vertical-align-middle text-right" rowspan="2">0.14</td>
<td class="vertical-align-middle text-right" rowspan="2">16.00</td>
<td class="vertical-align-middle text-right" rowspan="2">66.67%</td>
<td class="vertical-align-middle text-right">112.56</td>
<td class="vertical-align-middle">EUR</td>
<td class="vertical-align-middle text-right">1.95583</td>
<td class="vertical-align-middle text-right">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="2">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="2">220.14</td>
<td class="vertical-align-middle text-right" rowspan="2">1600.00</td>
<td class="vertical-align-middle text-right" rowspan="2">2057.89</td>
<td class="vertical-align-middle text-right" rowspan="2">200.00</td>
<td class="vertical-align-middle text-right">1693.42</td>
<td class="vertical-align-middle text-right" rowspan="2">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="2">1264.34</td>
<td class="vertical-align-middle text-right" rowspan="2">0.36</td>
</tr>
<tr style="color:" title="" class="missing-rate-row">
<td class="vertical-align-middle">Unassigned</td>
<td class="vertical-align-middle">Unassigned</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
0.00
</td>
<td class="vertical-align-middle">
BGN
</td>
<td class="vertical-align-middle text-right">
1.00000
</td>
<td class="vertical-align-middle text-right">
</td>
<td class="vertical-align-middle text-right">
564.47
</td>
</tr>
<tr style="color:" title="" class="missing-rate-row">
<td class="vertical-align-middle column-fixed" rowspan="1" style="left: 0px; background: none;">
Total
</td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle" rowspan="1"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">8.00</td>
<td class="vertical-align-middle text-right">0</td>
<td class="vertical-align-middle text-right">0</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
8
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class=" vertical-align-middle text-right">
0
</td>
<td class="vertical-align-middle text-right">
8
</td>
<td class="vertical-align-middle text-right" rowspan="1">32.00</td>
<td class="vertical-align-middle text-right" rowspan="1">176</td>
<td class="vertical-align-middle text-right" rowspan="1">24.00</td>
<td class="vertical-align-middle text-right" rowspan="1">0.14</td>
<td class="vertical-align-middle text-right" rowspan="1">16.00</td>
<td class="vertical-align-middle text-right" rowspan="1">66.67%</td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle"></td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle text-right"></td>
<td class="vertical-align-middle text-right" rowspan="1">3522.23</td>
<td class="vertical-align-middle text-right" rowspan="1">220.14</td>
<td class="vertical-align-middle text-right" rowspan="1">1600.00</td>
<td class="vertical-align-middle text-right" rowspan="1">2057.89</td>
<td class="vertical-align-middle text-right" rowspan="1">200.00</td>
<td class="vertical-align-middle text-right">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="1">2257.89</td>
<td class="vertical-align-middle text-right" rowspan="1">1264.34</td>
<td class="vertical-align-middle text-right" rowspan="1">0.36</td>
</tr>
</tbody></table>
table 单元格查找 FindByColumnHeaderAttribute
和 FindByColumnIndexAttribute
的标准 Atata 属性不适用于此类 table,因为行具有不同数量的 <td>
单元格元素因为 rowspan
.
我在 atata-samples
存储库中创建了单独的示例项目 https://github.com/atata-framework/atata-samples/tree/master/TableWithRowSpannedCells 来试验此类 table 并提供解决方案。我最终为您的 table 提供了 3 种方法。因此,请按照 link 查看有关它们的来源和详细信息。
这是使用 XPath 查找的第一种直接方法:
using Atata;
namespace AtataSamples.TableWithRowSpannedCells
{
using _ = TableUsingXPathPage;
[Url("table-with-row-spanned-cells")]
public class TableUsingXPathPage : Page<_>
{
public Table<UserRow, _> Users { get; private set; }
public class UserRow : TableRow<_>
{
[FindByXPath(XPathTo.RowSpannedCell, Index = 0)]
public Text<_> Name { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 2)]
[Format("yyyy-MM-dd")]
public Date<_> StartDate { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 8)]
public Text<_> ExpertiseLevel { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 0)]
public Text<_> Client { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 1)]
public Text<_> Project { get; private set; }
[FindByXPath(XPathTo.NonRowSpannedCell, Index = 16)]
public Number<_> DirectProjectCost { get; private set; }
[FindByXPath(XPathTo.RowSpannedCell, Index = 22)]
public Number<_> GrossMarginPercent { get; private set; }
private static class XPathTo
{
public const string RowSpannedCell = "(self::*[td[@rowspan]] | preceding-sibling::tr[td[@rowspan]])[last()]/td[@rowspan]";
public const string NonRowSpannedCell = "td[not(@rowspan)]";
}
}
}
}
我们的想法是检测和拆分两种类型的 <td>
单元格元素:有和没有 rowspan
属性。
- 可以在
<tr>
的范围内找到没有rowspan
的单元格:"td[not(@rowspan)]"
(请注意,这是将针对特定<tr>
执行的相对 XPath) - 带有
rowspan
的单元格在tr
中可能会丢失,在这种情况下,您需要在最近的包含rowspan
的前一个兄弟<tr>
中找到此单元格:"(self::*[td[@rowspan]] | preceding-sibling::tr[td[@rowspan]])[last()]/td[@rowspan]"
因此,您可以根据单元格的类型使用其中一个 XPath 来查找单元格,并在相同类型的行的范围内指定它的索引。
查看 Table with Row-Spanned Cells 示例以了解其他方法和详细信息。