diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2009-03-09 17:27:39 -0700 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2009-03-10 11:56:19 -0700 |
commit | 694998ee4fb8d257ba78424cab630846327a0889 (patch) | |
tree | 42639216568af741a4d484c486336131c1c7d6d5 /activesupport | |
parent | d4091d3bc79731f55491cfb51c604a66502c944f (diff) | |
download | rails-694998ee4fb8d257ba78424cab630846327a0889.tar.gz rails-694998ee4fb8d257ba78424cab630846327a0889.tar.bz2 rails-694998ee4fb8d257ba78424cab630846327a0889.zip |
Nokogiri backend for XmlMini
[#2190 state:committed]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG | 3 | ||||
-rw-r--r-- | activesupport/lib/active_support/xml_mini.rb | 4 | ||||
-rw-r--r-- | activesupport/lib/active_support/xml_mini/nokogiri.rb | 67 | ||||
-rw-r--r-- | activesupport/test/xml_mini/nokogiri_engine_test.rb | 112 | ||||
-rw-r--r-- | activesupport/test/xml_mini/rexml_engine_test.rb | 15 |
5 files changed, 200 insertions, 1 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 1d42000867..8c6e724606 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,6 +1,7 @@ *Edge* -* XmlMini supports libxml if available. #2084 [Bart ten Brinke] +* XmlMini supports LibXML and Nokogiri backends. #2084, #2190 [Bart ten Brinke, Aaron Patterson] + Example: XmlMini.backend = 'Nokogiri' *2.3.1 [RC2] (March 5, 2009)* diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index 99158e4ff7..0513c0d4d0 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -8,6 +8,10 @@ module ActiveSupport extend self delegate :parse, :to => :@backend + class << self + attr_reader :backend + end + def backend=(name) require "active_support/xml_mini/#{name.to_s.downcase}.rb" @backend = ActiveSupport.const_get("XmlMini_#{name}") diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb new file mode 100644 index 0000000000..bfafa29dd5 --- /dev/null +++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb @@ -0,0 +1,67 @@ +# = XML Mini Nokogiri implementation +module ActiveSupport + module XmlMini_Nokogiri #:nodoc: + extend self + + # Parse an XML Document string into a simple hash using libxml / nokogiri. + # string:: + # XML Document string to parse + def parse(string) + return {} if string.blank? + doc = Nokogiri::XML(string).to_hash + end + + module Conversions + module Document + def to_hash + root.to_hash + end + end + + module Node + CONTENT_ROOT = '__content__' + + # Convert XML document to hash + # + # hash:: + # Hash to merge the converted element into. + def to_hash(hash = {}) + hash[name] ||= attributes_as_hash + + walker = lambda { |child, memo, callback| + next if child.blank? + + if child.text? + (memo[CONTENT_ROOT] ||= '') << child.content + next + end + + name = child.name + + if memo[name] + memo[name] = [memo[name]].flatten + memo[name] << child.attributes_as_hash + else + memo[name] = child.attributes_as_hash + end + + # Recusively walk children + child.children.each { |c| callback.call(c, memo[name], callback) } + } + + children.each { |c| walker.call(c, hash[name], walker) } + hash + end + + def attributes_as_hash + Hash[*(attribute_nodes.map { |node| + [node.node_name, node.value] + }.flatten)] + end + end + end + + Nokogiri::XML::Document.send(:include, Conversions::Document) + Nokogiri::XML::Node.send(:include, Conversions::Node) + end +end diff --git a/activesupport/test/xml_mini/nokogiri_engine_test.rb b/activesupport/test/xml_mini/nokogiri_engine_test.rb new file mode 100644 index 0000000000..5c4002d34e --- /dev/null +++ b/activesupport/test/xml_mini/nokogiri_engine_test.rb @@ -0,0 +1,112 @@ +require 'abstract_unit' +require 'active_support/xml_mini' + + +begin + +require 'nokogiri' + +class NokogiriEngineTest < Test::Unit::TestCase + include ActiveSupport + + def setup + @default_backend = XmlMini.backend.to_s.split('_').last + XmlMini.backend = 'Nokogiri' + end + + def teardown + XmlMini.backend = @default_backend + end + + def test_setting_nokogiri_as_backend + XmlMini.backend = 'Nokogiri' + assert_equal XmlMini_Nokogiri, XmlMini.backend + end + + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse('')) + end + + def test_one_node_document_as_hash + assert_equal_rexml(<<-eoxml) + <products/> + eoxml + end + + def test_one_node_with_attributes_document_as_hash + assert_equal_rexml(<<-eoxml) + <products foo="bar"/> + eoxml + end + + def test_products_node_with_book_node_as_hash + assert_equal_rexml(<<-eoxml) + <products> + <book name="awesome" id="12345" /> + </products> + eoxml + end + + def test_products_node_with_two_book_nodes_as_hash + assert_equal_rexml(<<-eoxml) + <products> + <book name="awesome" id="12345" /> + <book name="america" id="67890" /> + </products> + eoxml + end + + def test_single_node_with_content_as_hash + assert_equal_rexml(<<-eoxml) + <products> + hello world + </products> + eoxml + end + + def test_children_with_children + assert_equal_rexml(<<-eoxml) + <root> + <products> + <book name="america" id="67890" /> + </products> + </root> + eoxml + end + + def test_children_with_text + assert_equal_rexml(<<-eoxml) + <root> + <products> + hello everyone + </products> + </root> + eoxml + end + + def test_children_with_non_adjacent_text + assert_equal_rexml(<<-eoxml) + <root> + good + <products> + hello everyone + </products> + morning + </root> + eoxml + end + + private + def assert_equal_rexml(xml) + XmlMini.backend = 'REXML' + hash = XmlMini.parse(xml) + + XmlMini.backend = 'Nokogiri' + + assert_equal(hash, XmlMini.parse(xml)) + end +end +rescue LoadError + # Yay, no errors +end diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb new file mode 100644 index 0000000000..a412d8ca05 --- /dev/null +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -0,0 +1,15 @@ +require 'abstract_unit' +require 'active_support/xml_mini' + +class REXMLEngineTest < Test::Unit::TestCase + include ActiveSupport + + def test_default_is_rexml + assert_equal XmlMini_REXML, XmlMini.backend + end + + def test_set_rexml_as_backend + XmlMini.backend = 'REXML' + assert_equal XmlMini_REXML, XmlMini.backend + end +end |