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, pattern_match_xpath)
click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 36 def initialize(xpath, pattern_match_xpath) @xpath = xpath @pattern_match_xpath = pattern_match_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 52 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? attribute comparison allows for e.g.: <SameName>
<SameName code="N"/>
</SameName>
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 48 def in?(node) @stack.detect { |item| item.name == node.name && item.attrs == node.attributes } end
inner_text()
click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 81 def inner_text dom_stubs[@stack].xpath(@xpath)&.inner_text end
leave(_node)
click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 56 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 63 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 131 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 94 def current_stack_match? parent_stack = @stack[0..-2] stack_match = if @pattern_match_xpath dom_stubs[@stack].root.children.find_all do |node| node.name =~ Regexp.new(@xpath) end.first else dom_stubs[@stack].at_xpath(@xpath) end return false unless stack_match parent_stack.empty? || xpath_not_in_parent_document?(dom_stubs[parent_stack]) 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 122 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 87 def in_empty_element? @stack.last.empty end
xpath_not_in_parent_document?(parent_document)
click to toggle source
# File lib/ndr_import/helpers/file/xml_streaming.rb, line 110 def xpath_not_in_parent_document?(parent_document) if @pattern_match_xpath parent_document.root.children.find_all do |node| node.name =~ Regexp.new(@xpath) end.first.nil? else !parent_document.at_xpath(@xpath) end end