feetwet
feetwet

Reputation: 3446

XPath doesn't work on subset in context but does in isolation

On the following XML:

<root>
    <h1">Annual Expense</h1>
    <div class="table-wrapper">
        <table>
            <tr>
                <td>Fees</td>
                <td>1.06%</td>
            </tr><tr>
                <td><b>Total:</b></td>
                <td class="right-align"><b>
                    <span class="summary-line">
                        1.57%
                    </span>
                </b></td>
            </tr>
        </table>
    </div>
</root>

I'm trying to get the Total value (1.57%). If I XPath query with //tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]] I get the desired XML block:

<td class="right-align">
    <b>
        <span class="summary-line">
            1.57%
        </span>
    </b>
</td>

And if I query for //*[not(*)]/text() against that block in isolation I get the desired result ("1.57%").

However, if I append try to concatenate the two queries (i.e., //tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]]/*[not(*)]/text()) and run against the full XML I get an empty result. Why?

Upvotes: 0

Views: 34

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167676

Your path //tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]] selects a td element node in your sample which has a b child element and span grandchild and your attempt to add a step with *[not(*)] to that path would select a child element of the td not having any further child. There is no such child, a step with * would select the b element, a further step with * the span element so you would need //tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]]/*/* to select the span grandchild or //tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]]//*[not(*)] to select any descendant element not having element content.

Upvotes: 1

Related Questions