How can I create a nokogiri case insensitive Xpath selector?

|▌冷眼眸甩不掉的悲伤 提交于 2019-11-28 08:19:13

Wrapped for legibility:

puts page.parser.xpath("
  //meta[
    translate(
      @name, 
      'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
      'abcdefghijklmnopqrstuvwxyz'
    ) = 'keywords'
  ]
").to_html

There is no "to lower case" function in XPath 1.0, so you have to use translate() for this kind of thing. Add accented letters as necessary.

Nokogiri allows custom XPath functions. The nokogiri docs that you link to show an inline class definition for when you're only using it once. If you have a lot of custom functions or if you use the case-insensitive match a lot, you may want to define it in a class.

class XpathFunctions

  def case_insensitive_equals(node_set, str_to_match)
    node_set.find_all {|node| node.to_s.downcase == str_to_match.to_s.downcase }
  end

end

Then call it like any other XPath function, passing in an instance of your class as the 2nd argument.

page.parser.xpath("//meta[case_insensitive_equals(@name,'keywords')]",
                  XpathFunctions.new).to_html

In your Ruby method, node_set will be bound to a Nokogiri::XML::NodeSet. In the case where you're passing in an attribute value like @name, it will be a NodeSet with a single Nokogiri::XML::Attr. So calling to_s on it gives you its value. (Alternatively, you could use node.value.)

Unlike using XPath translate where you have to specify every character, this works on all the characters and character encodings that Ruby works on.

Also, if you're interested in doing other things besides case-insensitive matching that XPath 1.0 doesn't support, it's just Ruby at this point. So this is a good starting point.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!