Skip to content

Partially support parenthesized xpath#317

Open
tompng wants to merge 1 commit into
ruby:masterfrom
tompng:fix_parentheses_predicate
Open

Partially support parenthesized xpath#317
tompng wants to merge 1 commit into
ruby:masterfrom
tompng:fix_parentheses_predicate

Conversation

@tompng
Copy link
Copy Markdown
Member

@tompng tompng commented May 22, 2026

Fix #25, and also reverts #122.

Adds a new path_stack operator :group

Copilot AI review requested due to automatic review settings May 22, 2026 15:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates REXML’s XPath parsing/evaluation to better handle predicates applied to parenthesized node-set expressions (e.g., (/path[p1])[p2]), addressing the node-set position semantics behind issue #25 and adjusting behavior introduced by #122.

Changes:

  • Fix predicate evaluation so positions are computed per nodeset (not across multiple nodesets), correcting cases like /div/div/test[1][2].
  • Add a parsing workaround for parenthesized node-set expressions by inserting a self::node() “separator” step to distinguish inner vs. outer predicates.
  • Expand XPath tests to cover nested predicate/parentheses scenarios and axis expressions wrapped in parentheses.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
test/xpath/test_base.rb Adds regression tests for nested predicates and parenthesized expressions.
lib/rexml/xpath_parser.rb Adjusts predicate evaluation to assign positions per nodeset during filtering.
lib/rexml/parsers/xpathparser.rb Inserts a self::node() separator after parenthesized node-set expressions to separate predicate scopes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/xpath/test_base.rb Outdated
matches = XPath.match(doc, '//div[1]/test|//div[2]/test[2]').map(&:text)
assert_equal ["ab", "cd", "gh"], matches
matches = XPath.match(doc, '(//div[1]/test|//div[2]/test)[2]').map(&:text)
assert_equal ["ab", "cd", "ef", "gh"], matches
Comment thread lib/rexml/parsers/xpathparser.rb Outdated
parsed.concat(n)
# For xpath like `(/path[predicate1][predicate2])[predicate3][predicate4]`,
# add a separator mark to distinguish predicates of the inner parentheses and the outer parentheses.
parsed << :self << :node if NODE_OPERATOR_TYPES.include?(n.first)
Comment thread lib/rexml/parsers/xpathparser.rb Outdated
Comment on lines +16 to +21
# Types that evaluates to nodeset
NODE_OPERATOR_TYPES = %i[
document self child literal attribute namespace parent ancestor
ancestor_or_self descendant_or_self descendant following_sibling
preceding_sibling preceding following union
]
@tompng tompng force-pushed the fix_parentheses_predicate branch 2 times, most recently from 1760158 to 22ed263 Compare May 22, 2026 17:01
Copilot AI review requested due to automatic review settings May 22, 2026 17:01
Add a new path_stack operator `:group`
@tompng tompng force-pushed the fix_parentheses_predicate branch from 22ed263 to 10bde7a Compare May 22, 2026 17:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread lib/rexml/xpath_parser.rb
Comment on lines +442 to +450
when :group
sub_expression = path_stack.shift
result = expr(sub_expression, nodeset, context)
if result.is_a?(Array)
# If result is a nodeset, apply following predicates
path_stack.unshift(:node)
nodeset = step(path_stack) do
[result]
end
Comment thread lib/rexml/xpath_parser.rb
sub_expression = path_stack.shift
result = expr(sub_expression, nodeset, context)
if result.is_a?(Array)
# If result is a nodeset, apply following predicates
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.

Node set predicate not working

2 participants