class NdrImport::Helpers::File::XmlStreaming::Cursor

Object to track state as the XML is iterated over, and detect when an element of interest is entered.

Constants

StackItem

wrapper to hold a representation of each element we descent into:

Public Class Methods

new(xpath) click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 36
def initialize(xpath)
  @xpath = xpath
  @stack = []
  @match_depth = nil
end

Public Instance Methods

enter(node) click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 47
def enter(node)
  @stack.push StackItem.new(node.name, node.attributes, node.empty_element?)
end
in?(node) click to toggle source

Has this cursor already passed inside a similar node?

# File lib/ndr_import/helpers/file/xml_streaming.rb, line 43
def in?(node)
  @stack.detect { |item| item.name == node.name }
end
leave(_node) click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 51
def leave(_node)
  @stack.pop
  @match_depth = nil if @match_depth && @stack.length < @match_depth
end
matches?() click to toggle source

Does the element that the cursor is currently on match what is being looked for?

# File lib/ndr_import/helpers/file/xml_streaming.rb, line 58
def matches?
  # Can't match again if we're inside a match already:
  return false if @matched_depth

  match = current_stack_match?

  # "empty element" matches are yielded immediately, without
  # tagging the stack as having matched, because there won't
  # be an equivalent closing tag to end the match with later.
  if in_empty_element?
    @stack.pop
  elsif match
    @match_depth = @stack.length
  end

  match
end

Private Instance Methods

add_items_to_dom(dom, items) click to toggle source

Helper to recursively build XML fragment.

# File lib/ndr_import/helpers/file/xml_streaming.rb, line 104
def add_items_to_dom(dom, items)
  item = items.shift
  dom.send(item.name, item.attrs) do
    add_items_to_dom(dom, items) if items.any?
  end
end
current_stack_match?() click to toggle source

Does the current state of the stack mean we've met the xpath criteria? Must be an exact match, not just matching a parent element in the DOM.

# File lib/ndr_import/helpers/file/xml_streaming.rb, line 85
def current_stack_match?
  parent_stack = @stack[0..-2]

  return false unless dom_stubs[@stack].at_xpath(@xpath)

  parent_stack.empty? || !dom_stubs[parent_stack].at_xpath(@xpath)
end
dom_stubs() click to toggle source

A cached collection of DOM fragments, to represent the structure necessary to use xpath to descend into the main document's DOM.

# File lib/ndr_import/helpers/file/xml_streaming.rb, line 95
def dom_stubs
  @dom_stubs ||= Hash.new do |hash, items|
    hash[items.dup] = Nokogiri::XML::Builder.new do |dom|
      add_items_to_dom(dom, items.dup)
    end.doc
  end
end
in_empty_element?() click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 78
def in_empty_element?
  @stack.last.empty
end