class Nokogiri::CSS::XPathVisitor
def visit_function node
def visit_function node msg = :"visit_function_#{node.value.first.gsub(/[(]/, '')}" return self.send(msg, node) if self.respond_to?(msg) case node.value.first when /^text\(/ 'child::text()' when /^self\(/ "self::#{node.value[1]}" when /^eq\(/ "position()=#{node.value[1]}" when /^(nth|nth-of-type)\(/ if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :NTH nth(node.value[1]) else "position()=#{node.value[1]}" end when /^nth-child\(/ if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :NTH nth(node.value[1], :child => true) else "count(preceding-sibling::*)=#{node.value[1].to_i-1}" end when /^nth-last-of-type\(/ if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :NTH nth(node.value[1], :last => true) else index = node.value[1].to_i - 1 index == 0 ? "position()=last()" : "position()=last()-#{index}" end when /^nth-last-child\(/ if node.value[1].is_a?(Nokogiri::CSS::Node) and node.value[1].type == :NTH nth(node.value[1], :last => true, :child => true) else "count(following-sibling::*)=#{node.value[1].to_i-1}" end when /^(first|first-of-type)\(/ "position()=1" when /^(last|last-of-type)\(/ "position()=last()" when /^contains\(/ "contains(.,#{node.value[1]})" when /^gt\(/ "position()>#{node.value[1]}" when /^only-child\(/ "last()=1" when /^comment\(/ "comment()" when /^has\(/ is_direct = node.value[1].value[0].nil? # e.g. "has(> a)", "has(~ a)", "has(+ a)" ".#{"//" if !is_direct}#{node.value[1].accept(self)}" else # non-standard. this looks like a function call. args = ['.'] + node.value[1..-1] "#{node.value.first}#{args.join(',')})" end end