nokogiri
nokogiri copied to clipboard
Add global XPath functions handler
What problem is this PR intended to solve?
Allow global definition of XPath functions, e.g.
module MyFunctions
def regex(node_set, pattern)
node_set.find_all { |node| node['some_attribute'] =~ /#{pattern}/ }
end
end
Nokogiri::XML::XPathFunctions.include(MyFunctions)
node.search('.//title[regex(., "\w+")]', 'div.employee:regex("[0-9]+")')
This is a revival of #464 with a different approach. Although that PR is shown as merged, I think that's a GitHub bug. The original implementation was mbklein/nokogiri@8fb3da3 which has not been merged.
Have you included adequate test coverage?
I think so. I refrained from adding tests which would overlap with existing tests, but I would be happy to add more, if you have suggestions.
Does this change affect the C or the Java implementations?
~No.~ Apparently, yes. The Java implementation injects XML namespaces into XPath queries based on the Ruby methods the function handler defines. Previously, that list of methods was derived from the function handler class, which omits methods delegated by SimpleDelegator
. Now the list of methods is derived directly from the function handler object.
Code Climate has analyzed commit c3376dd8 and detected 0 issues on this pull request.
The test coverage on the diff in this pull request is 100.0% (80% is the threshold).
This pull request will bring the total coverage in the repository to 93.5% (0.0% change).
View more on Code Climate.
Thank you for submitting this PR! I'll take a look as soon as I can, this is a super-busy week for me.
Sorry this has gone so long without review; I'm tagging it for v1.11.0 which I'm hoping to release at the end of 2019, so will review in that timeframe.
I've rebased this onto current main
.
I've added a require "delegate"
which was needed to not break downstream CI, e.g.
- https://github.com/sparklemotion/nokogiri/runs/8058997083?check_suite_focus=true
- https://github.com/sparklemotion/nokogiri/runs/8058997115?check_suite_focus=true
OK, the method lookup in the XmlXpathContext.java:evalute()
block doesn't work properly. I spent a few minutes exploring how to get the public methods out of the block but couldn't quite figure it out.
Here's the failing test that needs to be added:
def test_search_with_xpath_query_uses_global_custom_selectors_with_arguments_without_namespace
skip("Testing fallback behavior in JRuby") unless Nokogiri.jruby?
XPathFunctions.class_eval do
def our_filter(*args)
my_filter(*args)
end
end
set = @xml.search('//employee/address[our_filter(., "domestic", "Yes")]', @handler)
refute_empty(set)
set.each do |node|
assert_equal("Yes", node["domestic"])
end
end
I also want to point out that the intention is to deprecate use of custom XPath functions without the nokogiri:
prefix -- see #2147. We might reasonably wait until that lands and then take another look at this.
@flavorjones Oh wow, I forgot about this one! I am fine with waiting until after #2147 — no rush. Still, I was curious to see if I could get it working, so I pushed a commit to fix any failing tests, including the one you mentioned (test_search_with_xpath_query_uses_global_custom_selectors_with_arguments_without_namespace
).
Thank you! I'll take another look