Skip to content

Commit

Permalink
Minor cleanup (#3379)
Browse files Browse the repository at this point in the history
**What problem is this PR intended to solve?**

Some cleanup and refactoring that was originally in #3378 but is
generally valuable even if that PR doesn't land, so I split it out.
  • Loading branch information
flavorjones authored Dec 14, 2024
2 parents d11c148 + 5822532 commit c9b26b0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 65 deletions.
41 changes: 13 additions & 28 deletions ext/nokogiri/xml_xpath_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,7 @@ rb_xml_xpath_context_register_ns(VALUE rb_context, VALUE prefix, VALUE uri)
{
xmlXPathContextPtr c_context;

TypedData_Get_Struct(
rb_context,
xmlXPathContext,
&xml_xpath_context_type,
c_context
);
TypedData_Get_Struct(rb_context, xmlXPathContext, &xml_xpath_context_type, c_context);

xmlXPathRegisterNs(c_context,
(const xmlChar *)StringValueCStr(prefix),
Expand All @@ -160,12 +155,7 @@ rb_xml_xpath_context_register_variable(VALUE rb_context, VALUE name, VALUE value
xmlXPathContextPtr c_context;
xmlXPathObjectPtr xmlValue;

TypedData_Get_Struct(
rb_context,
xmlXPathContext,
&xml_xpath_context_type,
c_context
);
TypedData_Get_Struct(rb_context, xmlXPathContext, &xml_xpath_context_type, c_context);

xmlValue = xmlXPathNewCString(StringValueCStr(value));

Expand Down Expand Up @@ -428,34 +418,29 @@ rb_xml_xpath_context_evaluate(int argc, VALUE *argv, VALUE rb_context)
static VALUE
rb_xml_xpath_context_new(VALUE klass, VALUE rb_node)
{
xmlNodePtr node;
xmlNodePtr c_node;
xmlXPathContextPtr c_context;
VALUE rb_context;

Noko_Node_Get_Struct(rb_node, xmlNode, node);
Noko_Node_Get_Struct(rb_node, xmlNode, c_node);

#if LIBXML_VERSION < 21000
/* deprecated in 40483d0 */
xmlXPathInit();
#endif

c_context = xmlXPathNewContext(node->doc);
c_context->node = node;
c_context = xmlXPathNewContext(c_node->doc);
c_context->node = c_node;

xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI);
xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI);
xmlXPathRegisterFuncNS(
c_context,
(const xmlChar *)"css-class",
NOKOGIRI_BUILTIN_URI,
xpath_builtin_css_class
);
xmlXPathRegisterFuncNS(
c_context,
(const xmlChar *)"local-name-is",
NOKOGIRI_BUILTIN_URI,
xpath_builtin_local_name_is
);

xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"css-class", NOKOGIRI_BUILTIN_URI,
xpath_builtin_css_class);
xmlXPathRegisterFuncNS(c_context,
(const xmlChar *)"local-name-is", NOKOGIRI_BUILTIN_URI,
xpath_builtin_local_name_is);

rb_context = TypedData_Wrap_Struct(
klass,
Expand Down
66 changes: 32 additions & 34 deletions lib/nokogiri/xml/searchable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,35 +207,26 @@ def >(selector) # rubocop:disable Naming/BinaryOperatorParameterName

private

def css_internal(node, rules, handler, ns)
xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
end

def xpath_internal(node, paths, handler, ns, binds)
document = node.document
return NodeSet.new(document) unless document

if paths.length == 1
return xpath_impl(node, paths.first, handler, ns, binds)
def extract_params(params) # :nodoc:
handler = params.find do |param|
![Hash, String, Symbol].include?(param.class)
end
params -= [handler] if handler

NodeSet.new(document) do |combined|
paths.each do |path|
xpath_impl(node, path, handler, ns, binds).each { |set| combined << set }
end
hashes = []
while Hash === params.last || params.last.nil?
hashes << params.pop
break if params.empty?
end
end
ns, binds = hashes.reverse

def xpath_impl(node, path, handler, ns, binds)
ctx = XPathContext.new(node)
ctx.register_namespaces(ns)
path = path.gsub("xmlns:", " :") unless Nokogiri.uses_libxml?
ns ||= document.root&.namespaces || {}

binds&.each do |key, value|
ctx.register_variable(key.to_s, value)
end
[params, handler, ns, binds]
end

ctx.evaluate(path, handler)
def css_internal(node, rules, handler, ns)
xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
end

def css_rules_to_xpath(rules, ns)
Expand All @@ -254,22 +245,29 @@ def xpath_query_from_css_rule(rule, ns)
end.join(" | ")
end

def extract_params(params) # :nodoc:
handler = params.find do |param|
![Hash, String, Symbol].include?(param.class)
def xpath_internal(node, paths, handler, ns, binds)
document = node.document
return NodeSet.new(document) unless document

if paths.length == 1
return xpath_impl(node, paths.first, handler, ns, binds)
end
params -= [handler] if handler

hashes = []
while Hash === params.last || params.last.nil?
hashes << params.pop
break if params.empty?
NodeSet.new(document) do |combined|
paths.each do |path|
xpath_impl(node, path, handler, ns, binds).each { |set| combined << set }
end
end
ns, binds = hashes.reverse
end

ns ||= document.root&.namespaces || {}
def xpath_impl(node, path, handler, ns, binds)
ctx = XPathContext.new(node)
ctx.register_namespaces(ns)
ctx.register_variables(binds)

[params, handler, ns, binds]
path = path.gsub("xmlns:", " :") unless Nokogiri.uses_libxml?

ctx.evaluate(path, handler)
end
end
end
Expand Down
17 changes: 14 additions & 3 deletions lib/nokogiri/xml/xpath_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ class XPathContext
###
# Register namespaces in +namespaces+
def register_namespaces(namespaces)
namespaces.each do |k, v|
k = k.to_s.gsub(/.*:/, "") # strip off 'xmlns:' or 'xml:'
register_ns(k, v)
namespaces.each do |key, value|
key = key.to_s.gsub(/.*:/, "") # strip off 'xmlns:' or 'xml:'

register_ns(key, value)
end
end

def register_variables(binds)
return if binds.nil?

binds.each do |key, value|
key = key.to_s

register_variable(key, value)
end
end
end
Expand Down

0 comments on commit c9b26b0

Please sign in to comment.