Class: XmlNodeStream::Selector

Inherits:
Object
  • Object
show all
Defined in:
lib/xml_node_stream/selector.rb

Overview

Partial implementation of XPath selectors. Only abbreviated paths and the text() function are supported. The rest of XPath is unecessary in the context of a Ruby application since XPath is also a programming language. If you really need an XPath function, chances are you can just do it in the Ruby code.

Example selectors:

  • book - find all child book elements
  • book/author - find all author elements that are children of the book child elements
  • ../book - find all sibling book elements
  • */author - find all author elements that are children of any child elements
  • book//author - find all author elements that descendants at any level of book child elements
  • .//author - find all author elements that are descendants of the current element
  • /library/books/book - find all book elements with the full path /library/books/book
  • author/text() - get the text values of all author child elements

Defined Under Namespace

Classes: Matcher

Constant Summary collapse

XPATH_SEGMENT_REGEX =
/\A(\.\.?|\*|[a-zA-Z_][\w-]*|text\(\))(\|((\.\.?|\*|[a-zA-Z_][\w-]*|text\(\))))*\z/

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Selector

Create a selector. Path should be an abbreviated XPath string.

Parameters:

  • path (String)

    the XPath selector string

Raises:

  • (ArgumentError)

    if the path is invalid



24
25
26
27
28
# File 'lib/xml_node_stream/selector.rb', line 24

def initialize(path)
  raise ArgumentError, "XPath pattern cannot be empty" if path.nil? || path.empty?

  @parts = tokenize_path(path)
end

Instance Method Details

#find(node) ⇒ Array<Node>

Apply the selector to the current node. Note, if your path started with a /, it will be applied to the root node.

Parameters:

  • node (Node)

    the node to apply the selector to

Returns:

  • (Array<Node>)

    the matching nodes



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/xml_node_stream/selector.rb', line 35

def find(node)
  matched = [node]
  @parts.each do |part_matchers|
    context = matched
    matched = []

    part_matchers.each do |matcher|
      matched.concat(matcher.select(context))
    end

    break if matched.empty?
  end
  matched
end