diff options
author | Willem van Bergen <willem@vanbergen.org> | 2010-01-01 12:57:36 +0100 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2010-01-01 13:17:46 -0800 |
commit | 96a2b3905ce14df8f25b1646d3b110505bf8820b (patch) | |
tree | 4ff32801cc260b2298382686e0a725e741b8a4b9 /activesupport/lib/active_support/xml_mini/libxmlsax.rb | |
parent | d7f9b9fd244228d3503d7d37ac2f07365d54df3c (diff) | |
download | rails-96a2b3905ce14df8f25b1646d3b110505bf8820b.tar.gz rails-96a2b3905ce14df8f25b1646d3b110505bf8820b.tar.bz2 rails-96a2b3905ce14df8f25b1646d3b110505bf8820b.zip |
Added SAX-based parser for XmlMini, using LibXML
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
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 |