chameleon95
chameleon95

Reputation: 244

xPath/HTML: Select node based on related node

<html>
    <body>
        <table>
            <tr>
                <th>HeaderA</th>
                <th>HeaderB</th>
                <th>HeaderC</th>
                <th>HeaderD</th>
            </tr>
            <tr>
                <td>ContentA</td>
                <td>ContentB</td>
                <td>ContentC</td>
                <td>ContentD</td>
            </tr>
         </table>
    </body>
</html>

I am looking for the most efficient way to select the content 'td' node based on the heading in the corresponding 'th' node..

My current xPath expression..

/html/body/table/tr/td[count(/html/body/table/tr/th[text() = 'HeaderA']/preceding-sibling::*)+1]

Some questions..

Upvotes: 7

Views: 3600

Answers (4)

Mads Hansen
Mads Hansen

Reputation: 66781

Harmen's answer is exactly what you need for a pure XPATH solution.

If you are really concerned with performance, then you could define an XSLT key:

<xsl:key name="columns" match="/html/body/table/tr/th" use="text()"/>

and then use the key in your predicate filter:

/html/body/table/tr/td[count(key('columns', 'HeaderC')/preceding-sibling::th)+1]

However, I suspect you probably won't be able to see a measurable difference in performance unless you need to filter on columns a lot (e.g. for-each loops with checks for every row for a really large document).

Upvotes: 2

mst
mst

Reputation: 247

Perhaps you want position() and XPath axes?

Upvotes: 0

Harmen
Harmen

Reputation: 22446

  • It is possible to use relative paths inside count()
  • I have never heard of another way to find the node number...

Here is the code with relative xpath-code inside count()

/html/body/table/tr/td[count(../../tr/th[text()='HeaderC']/preceding-sibling::*)+1]

But well, it is not much shorter... It won't be shorter than this in my opinion:

//td[count(../..//th[text()='HeaderC']/preceding-sibling::*)+1]

Upvotes: 3

Eran Medan
Eran Medan

Reputation: 45775

I would have left Xpath aside... since I assume it was DOM parsed, I'd use a Map data structure, and match the nodes in either client side or server side (JavaScript / Java) manually.

Seems to me XPath is being streatched beyond its limit here.

Upvotes: 1

Related Questions