Module: Banzai::Querying

Defined in:
lib/banzai/querying.rb

Class Method Summary collapse

Class Method Details

.css(document, query, reference_options = {}) ⇒ Object

Searches a Nokogiri document using a CSS query, optionally optimizing it whenever possible.

document - A document/element to search. query - The CSS query to use. reference_options - A hash with nodes filter options

Returns an array of Nokogiri::XML::Element objects if location is specified in reference_options. Otherwise it would a Nokogiri::XML::NodeSet.


16
17
18
19
20
21
22
23
24
# File 'lib/banzai/querying.rb', line 16

def css(document, query, reference_options = {})
  # When using "a.foo" Nokogiri compiles this to "//a[...]" but
  # "descendant::a[...]" is quite a bit faster and achieves the same result.
  xpath = Nokogiri::CSS.xpath_for(query)[0].gsub(%r{^//}, 'descendant::')
  xpath = restrict_to_p_nodes_at_root(xpath) if filter_nodes_at_beginning?(reference_options)
  nodes = document.xpath(xpath)

  filter_nodes(nodes, reference_options)
end

.filter_nodes(nodes, reference_options) ⇒ Object


30
31
32
33
34
35
36
# File 'lib/banzai/querying.rb', line 30

def filter_nodes(nodes, reference_options)
  if filter_nodes_at_beginning?(reference_options)
    filter_nodes_at_beginning(nodes)
  else
    nodes
  end
end

.filter_nodes_at_beginning(nodes) ⇒ Object

Selects child nodes if they are present in the beginning among other siblings.

nodes - A Nokogiri::XML::NodeSet.

Returns an array of Nokogiri::XML::Element objects.


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/banzai/querying.rb', line 47

def filter_nodes_at_beginning(nodes)
  parents_and_nodes = nodes.group_by(&:parent)
  filtered_nodes = []

  parents_and_nodes.each do |parent, nodes|
    children = parent.children
    nodes    = nodes.to_a

    children.each do |child|
      next if child.text.blank?

      node = nodes.shift
      break unless node == child

      filtered_nodes << node
    end
  end

  filtered_nodes
end

.filter_nodes_at_beginning?(reference_options) ⇒ Boolean

Returns:

  • (Boolean)

38
39
40
# File 'lib/banzai/querying.rb', line 38

def filter_nodes_at_beginning?(reference_options)
  reference_options && reference_options[:location] == :beginning
end

.restrict_to_p_nodes_at_root(xpath) ⇒ Object


26
27
28
# File 'lib/banzai/querying.rb', line 26

def restrict_to_p_nodes_at_root(xpath)
  xpath.gsub('descendant::', './p/')
end