Skip to content

Primitive value should't be wrapped in an array#326

Merged
naitoh merged 2 commits into
ruby:masterfrom
tompng:primitive_array_bugfix
Jun 9, 2026
Merged

Primitive value should't be wrapped in an array#326
naitoh merged 2 commits into
ruby:masterfrom
tompng:primitive_array_bugfix

Conversation

@tompng

@tompng tompng commented Jun 5, 2026

Copy link
Copy Markdown
Member

Similar to #324
Values should be nodeset(Array) or primitive, not [primitive]

Also removes these workarounds related to primitive wrapped in array

# Workaround to handle single primitive value wrapped in an array
result = result[0] if result.kind_of? Array and result.length == 1

# Workaround to handle multiple primitive values wrapped in an array
# Arrays are always nodeset, so `if result.size > 0` is enough
if result.size > 0 and result.inject(false) {|k,s| s or k}

It works even wrapping with an array, but leaving it will be a blocker of implementing delayed nodeset ordering.

Copilot AI review requested due to automatic review settings June 5, 2026 17:03

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

Note

Copilot was unable to run its full agentic suite in this review.

Adjusts XPath evaluation return values and XPath function outputs for variable resolution and node naming/namespace helpers.

Changes:

  • Changes variable expression evaluation to return the variable value directly (instead of wrapping in an Array).
  • Updates namespace_uri and name XPath functions to early-return values from within get_namespace blocks and adds "" fallbacks.

Reviewed changes

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

File Description
lib/rexml/xpath_parser.rb Changes the return type of variable expression evaluation.
lib/rexml/functions.rb Reworks namespace_uri/name to return directly from block and adds empty-string fallbacks.

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

Comment thread lib/rexml/xpath_parser.rb
when :variable
var_name = path_stack.shift
return [@variables[var_name]]
return @variables[var_name]
Comment thread lib/rexml/functions.rb
Comment on lines +77 to +80
get_namespace( node_set ) do |node|
return node.namespace
end
""
Copilot AI review requested due to automatic review settings June 9, 2026 12:58
@tompng tompng force-pushed the primitive_array_bugfix branch from 542bd9d to 6189869 Compare June 9, 2026 12:58

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

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

Comment thread lib/rexml/xpath_parser.rb
when :variable
var_name = path_stack.shift
return [@variables[var_name]]
return @variables[var_name]
Comment thread lib/rexml/xpath_parser.rb
Comment on lines 534 to 543
result = expr(expression.dclone, [node], subcontext)
trace(:predicate_evaluate, expression, node, subcontext, result) if @debug
result = result[0] if result.kind_of? Array and result.length == 1
if result.kind_of? Numeric
if result == position
new_nodeset << node
end
elsif result.instance_of? Array
if result.size > 0 and result.inject(false) {|k,s| s or k}
if result.size > 0
new_nodeset << node
end
if result.size > 0
new_nodeset << node
end
Comment thread lib/rexml/functions.rb
Comment on lines +77 to +80
get_namespace( node_set ) do |node|
return node.namespace
end
""
Comment thread lib/rexml/functions.rb
Comment on lines 84 to +87
get_namespace( node_set ) do |node|
node.expanded_name
return node.expanded_name
end
""
Comment thread lib/rexml/xpath_parser.rb
when :variable
var_name = path_stack.shift
return [@variables[var_name]]
return @variables[var_name]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Returning nil may cause unintentional behavior. However, it was returning [nil] before, and it may also cause problem, so basically nothing has changed.

In XPath 1.0, only string | number | boolean | nodeset are allowed.
In Nokogiri, using undefined variable will raise Undefined variable: $foo (Nokogiri::XML::XPath::SyntaxError).
In JavaScript's document.execute, all variables are bound to empty string.

Ideally, REXML should validate variables somewhere, and need to decide how to handle undefined variables: fallback or raise. Although changing/deciding this may be out of scope of this pull request.

Ref: https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Basics

A VariableReference evaluates to the value to which the variable name is bound in the set of variable bindings in the context. It is an error if the variable name is not bound to any value in the set of variable bindings in the expression context.

@naitoh naitoh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

@naitoh naitoh merged commit 5f5a8a2 into ruby:master Jun 9, 2026
72 of 73 checks passed
naitoh pushed a commit that referenced this pull request Jun 9, 2026
Related to #326
Functions must return nodeset or a primitive value. Functions::text()
returning an array of string is a bug to be fixed. Although, `text()` in
xpath is resolved as `[:child, :text]`, it's not a function, so
Functions::text is unused.

Also removes `Functions::processing_instruction`. These are node-test,
not functions.
@tompng tompng deleted the primitive_array_bugfix branch June 9, 2026 15:59
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