diff options
Diffstat (limited to 'activesupport/lib/active_support/xml_mini/libxmlsax.rb')
-rw-r--r-- | activesupport/lib/active_support/xml_mini/libxmlsax.rb | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb new file mode 100644 index 0000000000..dba1f8755a --- /dev/null +++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb @@ -0,0 +1,84 @@ +require 'libxml' + +# = XmlMini LibXML implementation using a SAX-based parser +module ActiveSupport + module XmlMini_LibXMLSAX + extend self + + # Class that will build the hash while the XML document + # is being parsed using SAX events. + class HashBuilder + + include LibXML::XML::SaxParser::Callbacks + + CONTENT_KEY = '__content__'.freeze + HASH_SIZE_KEY = '__hash_size__'.freeze + + attr_reader :hash + + def current_hash + @hash_stack.last + end + + def on_start_document + @hash = {} + @hash_stack = [@hash] + end + + def on_end_document + raise "Parse stack not empty!" if @hash_stack.size > 1 + end + + def on_error(error_message) + raise LibXML::XML::Error, error_message + end + + def on_start_element(name, attrs = {}) + new_hash = { CONTENT_KEY => '' }.merge(attrs) + new_hash[HASH_SIZE_KEY] = new_hash.size + 1 + + case current_hash[name] + when Array then current_hash[name] << new_hash + when Hash then current_hash[name] = [current_hash[name], new_hash] + when nil then current_hash[name] = new_hash + end + + @hash_stack.push(new_hash) + end + + def on_end_element(name) + if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == '' + current_hash.delete(CONTENT_KEY) + end + @hash_stack.pop + end + + def on_characters(string) + current_hash[CONTENT_KEY] << string + end + + alias_method :on_cdata_block, :on_characters + end + + attr_accessor :document_class + self.document_class = HashBuilder + + def parse(data) + if !data.respond_to?(:read) + data = StringIO.new(data || '') + end + + char = data.getc + if char.nil? + {} + else + data.ungetc(char) + document = self.document_class.new + parser = LibXML::XML::SaxParser.io(data) + parser.callbacks = document + parser.parse + document.hash + end + end + end +end
\ No newline at end of file |