module Nokogiri::XML::Searchable
def at(*args)
result. +paths+ must be one or more XPath or CSS queries.
Search this object for +paths+, and return only the first
call-seq: search *paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]
##
def at(*args) search(*args).first end
def at_css(*args)
match. +rules+ must be one or more CSS selectors.
Search this object for CSS +rules+, and return only the first
call-seq: css *rules, [namespace-bindings, custom-pseudo-class]
#
def at_css(*args) css(*args).first end
def at_xpath(*args)
match. +paths+ must be one or more XPath queries.
Search this node for XPath +paths+, and return only the first
call-seq: xpath *paths, [namespace-bindings, variable-bindings, custom-handler-class]
#
def at_xpath(*args) xpath(*args).first end
def css(*args)
(e.g., "H1" is distinct from "h1").
found in an XML document, where tags names are case-sensitive
will match only lowercase CSS queries. However, "H1" might be
an HTML document, you'll never find anything, since HTML tags
to your document type. That is, if you're looking for "H1" in
Note that the CSS query string is case-sensitive with regards
}.new)
end
node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
def regex node_set, regex
node.css('title:regex("\w+")', Class.new {
arguments are ones that you pass in. For example:
method will be the current matching NodeSet. Any other
pseudo class you want defined. The first argument to the
custom pseudo classes, create a class and implement the custom
Custom CSS pseudo classes may also be defined. To define
node.css('bike|tire', {'bike' => 'http://schwinn.com/'})
A hash of namespace bindings may be appended. For example:
node.css('div + p.green', 'div#one')
node.css('body h1.bold')
node.css('title')
selectors. For example:
Search this object for CSS +rules+. +rules+ must be one or more CSS
call-seq: css *rules, [namespace-bindings, custom-pseudo-class]
##
def css(*args) rules, handler, ns, _ = extract_params(args) css_internal self, rules, handler, ns end
def css_internal(node, rules, handler, ns)
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)
def css_rules_to_xpath(rules, ns) rules.map { |rule| xpath_query_from_css_rule(rule, ns) } end
def extract_params(params) # :nodoc:
def extract_params(params) # :nodoc: handler = params.find do |param| ![Hash, String, Symbol].include?(param.class) end params -= [handler] if handler hashes = [] while Hash === params.last || params.last.nil? hashes << params.pop break if params.empty? end ns, binds = hashes.reverse ns ||= document.root ? document.root.namespaces : {} [params, handler, ns, binds] end
def search(*args)
)
}.new
end
node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
def regex node_set, regex
Class.new {
node.search('.//title[regex(., "\w+")]', 'div.employee:regex("[0-9]+")'
appear anywhere in the argument list. For example:
arguments are ones that you pass in. Note that this class may
to the method will be the current matching NodeSet. Any other
implement the function you want to define. The first argument
defined. To define custom functions create a class and
Custom XPath functions and CSS pseudo-selectors may also be
node.search('.//address[@domestic=$value]', nil, {:value => 'Yes'})
appended to the namespace bindings. For example:
For XPath queries, a hash of variable bindings may also be
node.search('bike|tire', {'bike' => 'http://schwinn.com/'})
node.search('.//bike:tire', {'bike' => 'http://schwinn.com/'})
A hash of namespace bindings may be appended:
node.search("div.employee", ".//title")
Search this object for +paths+. +paths+ must be one or more XPath or CSS queries:
call-seq: search *paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]
##
def search(*args) paths, handler, ns, binds = extract_params(args) xpaths = paths.map(&:to_s).map do |path| (path =~ LOOKS_LIKE_XPATH) ? path : xpath_query_from_css_rule(path, ns) end.flatten.uniq xpath(*(xpaths + [ns, handler, binds].compact)) end
def xpath(*args)
}.new)
end
node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
def regex node_set, regex
node.xpath('.//title[regex(., "\w+")]', Class.new {
argument list. For example:
you pass in. Note that this class may appear anywhere in the
current matching NodeSet. Any other arguments are ones that
to define. The first argument to the method will be the
functions create a class and implement the function you want
Custom XPath functions may also be defined. To define custom
node.xpath('.//address[@domestic=$value]', nil, {:value => 'Yes'})
A hash of variable bindings may also be appended to the namespace bindings. For example:
node.xpath('.//xmlns:name', node.root.namespaces)
node.xpath('.//foo:name', {'foo' => 'http://example.org/'})
A hash of namespace bindings may be appended. For example:
node.xpath('.//title')
queries.
Search this node for XPath +paths+. +paths+ must be one or more XPath
call-seq: xpath *paths, [namespace-bindings, variable-bindings, custom-handler-class]
##
def xpath(*args) paths, handler, ns, binds = extract_params(args) xpath_internal self, paths, handler, ns, binds end
def xpath_impl(node, path, handler, ns, binds)
def xpath_impl(node, path, handler, ns, binds) ctx = XPathContext.new(node) ctx.register_namespaces(ns) path = path.gsub(/xmlns:/, " :") unless Nokogiri.uses_libxml? binds.each do |key, value| ctx.register_variable key.to_s, value end if binds ctx.evaluate(path, handler) end
def xpath_internal(node, paths, handler, ns, binds)
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 NodeSet.new(document) do |combined| paths.each do |path| xpath_impl(node, path, handler, ns, binds).each { |set| combined << set } end end end
def xpath_query_from_css_rule(rule, ns)
def xpath_query_from_css_rule(rule, ns) visitor = Nokogiri::CSS::XPathVisitorOptimallyUseBuiltins.new self.class::IMPLIED_XPATH_CONTEXTS.map do |implied_xpath_context| CSS.xpath_for(rule.to_s, {:prefix => implied_xpath_context, :ns => ns, :visitor => visitor}) end.join(" | ") end