Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds an xpathfunc that performs relative
id
lookups.There are two ways of doing those:
sel.xpath('id("foo")')
under the hood performs a dictionary lookup and thus is blazingly fast, however there's no way to limit the nodeset to search in.sel.xpath('//*[@id="foo"]')
one can limit the nodeset the way they like, however it has to traverse all the matching nodes, and thus is a lot slowerrel-id
function, presented in this PR, attempts to achieve some middle ground: it does theid
lookup under the hood, but then checks the result to be in the specified nodeset, i.e. all following statements return the same results:Naturally, it's a Python-level xpathfunc, so "native" solutions that involve
id
andancestor
are faster, but it's still more performant than[@id="foo"]
and.css("div #foo")
(that expands to[@id="foo"]
):The benchmark is available here. Also,
sel.xpath("//div").xpath("rel-id('masthead')")
andsel.xpath("//div|//span").xpath("rel-id('masthead')")
are very slow because of the number of items for whichrel-id
is invoked.One particular situation when
rel-id
is helpful, is when you pre-select a subset of the document and then look in its descendants:The
sel2.xpath('id("bar")[set:intersection(ancestor::*, .)]')
approach won't work here, because the dot inside the square brackets already meansid("bar")
rather thanid("foo")
.