 <p>I got this after more trial and error: <code>'/table/tbody/tr[preceding-sibling::tr[th/text()="First header"] = preceding-sibling::tr[th][1]]'</code> Which translates to English: get all rows preceded by the "First header" row where that row is also the first preceding row that contains a header.</p>