Skip to content

Stop fallback to XPath.match in FunctionsClass#send - #364

Merged
naitoh merged 1 commit into
ruby:masterfrom
tompng:remove_functions_calling_match
Aug 31, 2026
Merged

Stop fallback to XPath.match in FunctionsClass#send#364
naitoh merged 1 commit into
ruby:masterfrom
tompng:remove_functions_calling_match

Conversation

@tompng

@tompng tompng commented Aug 27, 2026

Copy link
Copy Markdown
Member

Related to #342, I found one more contamination path.

Return value of xpath function should be either number, string, boolean or nodeset. But the fallback path returns XPath.match(unregistered_function_name) which may return number/string/boolean wrapped in an array. (#353)
Instead of rejecting these invalid value types or unwrapping the array, simply removing the XPath-
noncompliant behavior is better.

The TODO comment below is kept because falling back to [] instead of raising error may be still not XPath spec behavior.

# TODO: Maybe, this is not XPath spec behavior.
# This behavior must be reconsidered.

Related bugs/glitch (though it's probably a combination of bug in REXML::Parsers::XPathParser)

REXML::XPath::match(REXML::Document.new('<root/>'), "/foo[1-2()]")
#=> []
REXML::XPath::match(REXML::Document.new('<root/>'), "/root[1-2()]")
#=> Garbage component exists at the end: <_2>: <1_2> (REXML::ParseException)

# Invalid type contamination
REXML::XPath::match(REXML::Document.new('<root/>'), "41()/a")
#=> undefined method 'node_type' for an instance of Integer (NoMethodError)

REXML::XPath::match(REXML::Document.new('<local-namae/>'), "local-namae()")
# => []
REXML::XPath::match(REXML::Document.new('<local_namae/>'), "local-namae()")
# => [<local_namae/>]

Return value of xpath function should be either number, string, boolean or nodeset.
But the fallback path returns `XPath.match(unregistered_function_name)` which may return number/string/boolean wrapped in an array.
Instead of rejecting these invalid value types or unwrapping the array, simply removing the XPath-noncompliant behavior is better.
Copilot AI lite review requested due to automatic review settings August 27, 2026 16:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This pull request removes the non-standard fallback behavior where an unregistered XPath function call could implicitly be treated as an element lookup via XPath.match, which could also contaminate return types (e.g., arrays wrapping scalars). The change aligns function evaluation more closely with XPath expectations by returning an empty nodeset for unknown functions.

Changes:

  • Update FunctionsClass#send to return [] for unregistered functions instead of falling back to XPath.match(...).
  • Adjust function tests to assert nil/empty results for unknown functions and add coverage for previously problematic cases (e.g., "42()").

Reviewed changes

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

File Description
lib/rexml/functions.rb Removes XPath.match fallback for unknown functions and returns an empty nodeset instead.
test/functions/test_base.rb Updates expectations for unknown functions and adds assertions preventing invalid return type contamination.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@naitoh
naitoh merged commit 6d21fff into ruby:master Aug 31, 2026
71 checks passed
@naitoh

naitoh commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Thanks!

@tompng
tompng deleted the remove_functions_calling_match branch August 31, 2026 03:08
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