Skip to content

Conversation

@mislav
Copy link
Contributor

@mislav mislav commented Nov 9, 2025

The XPath expression with chained predicates on the ancestor axis was not working correctly. For example:

//*[@itemprop="author"][ancestor::*[@itemscope][1][@itemtype="Comment"]]

This expression should find all elements with @itemprop="author" whose first @itemscope ancestor has @itemtype="Comment". However, it was returning 0 results instead of the expected elements.

Root cause:

  1. ancestorQuery.table (deduplication table) was persisting across Evaluate() calls, preventing ancestors from being found for subsequent input contexts.
  2. filterQuery.positmap (position map) was not being reset during Evaluate(), causing position tracking to be incorrect when the same predicate query was reused for multiple input nodes.

Fix:

  • Reset ancestorQuery.table to nil in Evaluate() to ensure clean state for each evaluation
  • Reset filterQuery.positmap to nil in Evaluate() to ensure clean state for each evaluation

These changes ensure that when a predicate query is evaluated multiple times (once for each candidate node), the internal state is properly reset, allowing the query to work correctly for each evaluation.

💁 Unit test by Mislav
🤖 Implementation by Claude Code

The XPath expression with chained predicates on the ancestor axis was not
working correctly. For example:
  //*[@itemprop="author"][ancestor::*[@itemscope][1][@itemtype="Comment"]]

This expression should find all elements with @itemprop="author" whose first
@itemscope ancestor has @itemtype="Comment". However, it was returning 0
results instead of the expected elements.

Root cause:
1. ancestorQuery.table (deduplication table) was persisting across Evaluate()
   calls, preventing ancestors from being found for subsequent input contexts.
2. filterQuery.positmap (position map) was not being reset during Evaluate(),
   causing position tracking to be incorrect when the same predicate query was
   reused for multiple input nodes.

Fix:
- Reset ancestorQuery.table to nil in Evaluate() to ensure clean state for
  each evaluation
- Reset filterQuery.positmap to nil in Evaluate() to ensure clean state for
  each evaluation

These changes ensure that when a predicate query is evaluated multiple times
(once for each candidate node), the internal state is properly reset, allowing
the query to work correctly for each evaluation.

💁 Unit test by Mislav
🤖 Implementation by [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coveralls
Copy link

Coverage Status

coverage: 78.01% (+0.03%) from 77.98%
when pulling 02c01b0 on mislav:fix-ancestor-predicate-chain
into 511abd5 on antchfx:master.

@zhengchun zhengchun merged commit 3cbab97 into antchfx:master Nov 10, 2025
3 checks passed
mislav added a commit to mislav/htmlquery that referenced this pull request Nov 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants