I have the following HTML code:
<table>
<tbody>
<tr>
<th class="colhead" nowrap="nowrap">Update</th>
<th class="colhead" nowrap="nowrap">Card No</th>
</tr>
<tr>
<td nowrap="nowrap"><a href="/admin?cpm_id=1043">
Update</a></td>
<td nowrap="nowrap">4987 6543 2109 8769</td>
</tr>
<tr>
<td nowrap="nowrap"><a href="/admin?cpm_id=905">
Update</a></td>
<td nowrap="nowrap">5123 4567 8901 2346</td>
</tr>
</tbody>
My question is if I know the value of the 'Card No' element, how can I get the XPath of the Update link? For example, If I know the Card No is "5123 4567 8901 2346", how can I get the XPath of the link element "<a href="/admin?cpm_id=905">"
?
Update from comments
I'm using an automation test tool
called QTP. I need to get the XPath of
the update link element to identify it
on the webpage based on the value of
the Credit Card number. What I'm after
is to get the XPath such
as"/html/body/table/tbody/tr[3]/td[1]/a".
However, this is the static path of
the update link element. I would like
to be able to get the XPath based on a
Credit Card number.
This is not a difficult task for XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pCardNo" select=
"'5123 4567 8901 2346'"/>
<xsl:template match="/">
<xsl:variable name="vNode" select=
"/*/*/tr[td[2] = $pCardNo]/td[1]
/a/ancestor-or-self::*"/>
<xsl:apply-templates select="$vNode" mode="path"/>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
<xsl:variable name="vnumPrecSiblings" select=
"count(preceding-sibling::*[name()=name(current())])"/>
<xsl:variable name="vnumFollSiblings" select=
"count(following-sibling::*[name()=name(current())])"/>
<xsl:if test="$vnumPrecSiblings or $vnumFollSiblings">
<xsl:value-of select=
"concat('[', $vnumPrecSiblings +1, ']')"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<table>
<tbody>
<tr>
<th class="colhead" nowrap="nowrap">Update</th>
<th class="colhead" nowrap="nowrap">Card No</th>
</tr>
<tr>
<td nowrap="nowrap">
<a href="/admin?cpm_id=1043"> Update</a>
</td>
<td nowrap="nowrap">4987 6543 2109 8769</td>
</tr>
<tr>
<td nowrap="nowrap">
<a href="/admin?cpm_id=905"> Update</a>
</td>
<td nowrap="nowrap">5123 4567 8901 2346</td>
</tr>
</tbody>
</table>
the wanted, correct result is produced:
/table/tbody/tr[3]/td[1]/a
Dimitre's answer is good for an XSLT solution but just for completeness, here is another perspective. Since the data is in a table with uniform structure, in a sense the XPath for any one element is the same when you consider the card number as a parameter. In C# for example, the string.Format
method uses {0}
as a placeholder, as shown in the XPATH_TEMPLATE below. Simply fill in the place holder in this template with the card number to get the requisite XPath expression.
string XPATH_TEMPLATE =
"//td[normalize-space(.)='{0}']/preceding-sibling::td/a";
string CardNumber = "4987 6543 2109 8769";
string XPathExpression = string.Format(XPATH_TEMPLATE, CardNumber);
The above yields this resulting XPath expression:
//td[normalize-space(.)='4987 6543 2109 8769']/preceding-sibling::td/a
So whether you are working in XSLT or C# or something else, this flavor of XPath is more meaningful (than e.g. /table/tbody/tr[3]/td[1]/a) because it is self-contained with context information.
Ran across a concept called bookmarklets. Using the given bookmarklets on your HTML code produced the result, /HTML/BODY/TABLE/TBODY/TR[3]/TD[1]/A.
The URL is Equivalent of Firebug's "Copy XPath" in Internet Explorer?
Executing the bookmarks on the name and email edit boxes on this page produces
//INPUT[@id='display-name']
//INPUT[@id='m-address']
Hope this helps