module Nokogiri::XML::Searchable - nokogiri-1.15.2 Documentation

# module Nokogiri::XML::Searchable

The `Searchable` module declares the interface used for searching your DOM.

It implements the public methods `search`, `css`, and `xpath`, as well as allowing specific implementations to specialize some of the important behaviors.

### Constants

LOOKS_LIKE_XPATH

  Regular expression used by `Searchable#search` to determine if a query string is `CSS` or `XPath`

### Private Instance Methods

css_internal(node, rules, handler, ns) click to toggle source

    # File lib/nokogiri/xml/searchable.rb, line 210
    def css_internal(node, rules, handler, ns)
      xpath_internal(node, css_rules_to_xpath(rules, ns), handler, ns, nil)
    end

css_rules_to_xpath(rules, ns) click to toggle source

    # File lib/nokogiri/xml/searchable.rb, line 241
    def css_rules_to_xpath(rules, ns)
      rules.map { |rule| xpath_query_from_css_rule(rule, ns) }
    end

xpath_impl(node, path, handler, ns, binds) click to toggle source

    # File lib/nokogiri/xml/searchable.rb, line 229
    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

      ctx.evaluate(path, handler)
    end

xpath_internal(node, paths, handler, ns, binds) click to toggle source

    # File lib/nokogiri/xml/searchable.rb, line 214
    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

xpath_query_from_css_rule(rule, ns) click to toggle source

    # File lib/nokogiri/xml/searchable.rb, line 245
    def xpath_query_from_css_rule(rule, ns)
      visitor = Nokogiri::CSS::XPathVisitor.new(
        builtins: Nokogiri::CSS::XPathVisitor::BuiltinsConfig::OPTIMAL,
        doctype: document.xpath_doctype,
      )
      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

## Searching via XPath or CSS Queries

↑ top

### Public Instance Methods

%(*args)
Alias for: at
/(*args)
Alias for: search
>(selector) → NodeSet click to toggle source

Search this node’s immediate children using `CSS` selector `selector`

    # File lib/nokogiri/xml/searchable.rb, line 201
    def >(selector) # rubocop:disable Naming/BinaryOperatorParameterName
      ns = (document.root&.namespaces || {})
      xpath(CSS.xpath_for(selector, prefix: "./", ns: ns).first)
    end

at(*paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]) click to toggle source

Search this object for `paths`, and return only the first result. `paths` must be one or more `XPath` or `CSS` queries.

See `Searchable#search` for more information.

    # File lib/nokogiri/xml/searchable.rb, line 74
    def at(*args)
      search(*args).first
    end

Also aliased as: %
at_css(*rules, [namespace-bindings, custom-pseudo-class]) click to toggle source

Search this object for `CSS` `rules`, and return only the first match. `rules` must be one or more `CSS` selectors.

See `Searchable#css` for more information.

    # File lib/nokogiri/xml/searchable.rb, line 143
    def at_css(*args)
      css(*args).first
    end

at_xpath(*paths, [namespace-bindings, variable-bindings, custom-handler-class]) click to toggle source

Search this node for `XPath` `paths`, and return only the first match. `paths` must be one or more `XPath` queries.

See `Searchable#xpath` for more information.

    # File lib/nokogiri/xml/searchable.rb, line 193
    def at_xpath(*args)
      xpath(*args).first
    end

css(*rules, [namespace-bindings, custom-pseudo-class]) click to toggle source

Search this object for `CSS` `rules`. `rules` must be one or more `CSS` selectors. For example:

    node.css('title')
    node.css('body h1.bold')
    node.css('div + p.green', 'div#one')

A hash of namespace bindings may be appended. For example:

    node.css('bike|tire', {'bike' => 'http://schwinn.com/'})

💡 Custom `CSS` pseudo classes may also be defined which are mapped to a custom `XPath` function. To define custom pseudo classes, create a class and implement the custom pseudo class you want defined. The first argument to the method will be the matching context `NodeSet`. Any other arguments are ones that you pass in. For example:

    handler = Class.new {
      def regex(node_set, regex)
        node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
      end
    }.new
    node.css('title:regex("\w+")', handler)

💡 Some `XPath` syntax is supported in `CSS` queries. For example, to query for an attribute:

    node.css('img > @href') # returns all +href+ attributes on an +img+ element
    node.css('img / @href') # same

    # ⚠ this returns +class+ attributes from all +div+ elements AND THEIR CHILDREN!
    node.css('div @class')

    node.css

💡 Array-like syntax is supported in `CSS` queries as an alternative to using +:nth-child()+.

⚠ NOTE that indices are 1-based like `:nth-child` and not 0-based like Ruby Arrays. For example:

    # equivalent to 'li:nth-child(2)'
    node.css('li[2]') # retrieve the second li element in a list

⚠ NOTE that the `CSS` query string is case-sensitive with regards to your document type. `HTML` tags will match only lowercase `CSS` queries, so if you search for “H1” in an `HTML` document, you’ll never find anything. However, “H1” might be found in an `XML` document, where tags names are case-sensitive (e.g., “H1” is distinct from “h1”).

    # File lib/nokogiri/xml/searchable.rb, line 129
    def css(*args)
      rules, handler, ns, _ = extract_params(args)

      css_internal(self, rules, handler, ns)
    end

search(*paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]) click to toggle source

Search this object for `paths`. `paths` must be one or more `XPath` or `CSS` queries:

    node.search("div.employee", ".//title")

A hash of namespace bindings may be appended:

    node.search('.//bike:tire', {'bike' => 'http://schwinn.com/'})
    node.search('bike|tire', {'bike' => 'http://schwinn.com/'})

For `XPath` queries, a hash of variable bindings may also be appended to the namespace bindings. For example:

    node.search('.//address[@domestic=$value]', nil, {:value => 'Yes'})

💡 Custom `XPath` functions and `CSS` pseudo-selectors may also be defined. To define custom functions create a class and implement the function you want to define, which will be in the ‘nokogiri` namespace in `XPath` queries.

The first argument to the method will be the current matching `NodeSet`. Any other arguments are ones that you pass in. Note that this class may appear anywhere in the argument list. For example:

    handler = Class.new {
      def regex node_set, regex
        node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
      end
    }.new
    node.search('.//title[nokogiri:regex(., "\w+")]', 'div.employee:regex("[0-9]+")', handler)

See `Searchable#xpath` and `Searchable#css` for further usage help.

    # File lib/nokogiri/xml/searchable.rb, line 54
    def search(*args)
      paths, handler, ns, binds = extract_params(args)

      xpaths = paths.map(&:to_s).map do |path|
        LOOKS_LIKE_XPATH.match?(path) ? path : xpath_query_from_css_rule(path, ns)
      end.flatten.uniq

      xpath(*(xpaths + [ns, handler, binds].compact))
    end

Also aliased as: /
xpath(*paths, [namespace-bindings, variable-bindings, custom-handler-class]) click to toggle source

Search this node for `XPath` `paths`. `paths` must be one or more `XPath` queries.

    node.xpath('.//title')

A hash of namespace bindings may be appended. For example:

    node.xpath('.//foo:name', {'foo' => 'http://example.org/'})
    node.xpath('.//xmlns:name', node.root.namespaces)

A hash of variable bindings may also be appended to the namespace bindings. For example:

    node.xpath('.//address[@domestic=$value]', nil, {:value => 'Yes'})

💡 Custom `XPath` functions may also be defined. To define custom functions create a class and implement the function you want to define, which will be in the ‘nokogiri` namespace.

The first argument to the method will be the current matching `NodeSet`. Any other arguments are ones that you pass in. Note that this class may appear anywhere in the argument list. For example:

    handler = Class.new {
      def regex(node_set, regex)
        node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ }
      end
    }.new
    node.xpath('.//title[nokogiri:regex(., "\w+")]', handler)

    # File lib/nokogiri/xml/searchable.rb, line 179
    def xpath(*args)
      paths, handler, ns, binds = extract_params(args)

      xpath_internal(self, paths, handler, ns, binds)
    end