File: active_support/xml_mini/nokogirisax.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: ActiveSupport#4
  module: XmlMini_NokogiriSAX#5
extends
  XmlMini_NokogiriSAX ( ActiveSupport )
has properties
attribute: document_class [RW] #62
method: parse / 1 #65
  class: HashBuilder#10
inherits from
  Document ( Nokogiri::XML::SAX )
has properties
constant: CONTENT_KEY #12
constant: HASH_SIZE_KEY #13
attribute: hash [R] #15
method: current_hash #17
method: start_document #21
method: end_document #26
method: error / 1 #30
method: start_element / 2 #34
method: end_element / 1 #48
method: characters / 1 #55

Code

   1  require 'nokogiri'
   2 
   3  # = XmlMini Nokogiri implementation using a SAX-based parser
   4  module ActiveSupport
   5    module XmlMini_NokogiriSAX
   6      extend self
   7 
   8      # Class that will build the hash while the XML document
   9      # is being parsed using SAX events.
  10      class HashBuilder < Nokogiri::XML::SAX::Document
  11 
  12        CONTENT_KEY   = '__content__'.freeze
  13        HASH_SIZE_KEY = '__hash_size__'.freeze
  14 
  15        attr_reader :hash
  16 
  17        def current_hash
  18          @hash_stack.last
  19        end
  20 
  21        def start_document
  22          @hash = {}
  23          @hash_stack = [@hash]
  24        end
  25 
  26        def end_document
  27          raise "Parse stack not empty!" if @hash_stack.size > 1
  28        end
  29 
  30        def error(error_message)
  31          raise error_message
  32        end
  33 
  34        def start_element(name, attrs = [])
  35          new_hash = { CONTENT_KEY => '' }
  36          new_hash[attrs.shift] = attrs.shift while attrs.length > 0
  37          new_hash[HASH_SIZE_KEY] = new_hash.size + 1
  38 
  39          case current_hash[name]
  40            when Array then current_hash[name] << new_hash
  41            when Hash  then current_hash[name] = [current_hash[name], new_hash]
  42            when nil   then current_hash[name] = new_hash
  43          end
  44 
  45          @hash_stack.push(new_hash)
  46        end
  47 
  48        def end_element(name)
  49          if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == ''
  50            current_hash.delete(CONTENT_KEY)
  51          end
  52          @hash_stack.pop
  53        end
  54 
  55        def characters(string)
  56          current_hash[CONTENT_KEY] << string
  57        end
  58 
  59        alias_method :cdata_block, :characters
  60      end
  61 
  62      attr_accessor :document_class
  63      self.document_class = HashBuilder
  64 
  65      def parse(string)
  66        return {} if string.blank?
  67        document = self.document_class.new
  68        parser = Nokogiri::XML::SAX::Parser.new(document)
  69        parser.parse(string)
  70        document.hash
  71      end
  72    end
  73  en