aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/xml_mini
diff options
context:
space:
mode:
authorWillem van Bergen <willem@vanbergen.org>2010-01-01 12:57:36 +0100
committerJeremy Kemper <jeremy@bitsweat.net>2010-01-01 13:17:46 -0800
commit96a2b3905ce14df8f25b1646d3b110505bf8820b (patch)
tree4ff32801cc260b2298382686e0a725e741b8a4b9 /activesupport/lib/active_support/xml_mini
parentd7f9b9fd244228d3503d7d37ac2f07365d54df3c (diff)
downloadrails-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')
-rw-r--r--activesupport/lib/active_support/xml_mini/libxmlsax.rb84
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