diff options
author | Jacob Lauemoeller <jacob.lauemoeller@iteray.com> | 2009-10-02 16:34:28 +0200 |
---|---|---|
committer | Michael Koziarski <michael@koziarski.com> | 2009-10-15 10:54:30 +1300 |
commit | fc46c9b2207c62d4b029c2c891c61fc660c0b627 (patch) | |
tree | 8f3923fd4d49fc3026a5764a7bb3b05911eae8de /activesupport | |
parent | 3fa7e2fc98235fdb6abba1d0e703464e880aa2af (diff) | |
download | rails-fc46c9b2207c62d4b029c2c891c61fc660c0b627.tar.gz rails-fc46c9b2207c62d4b029c2c891c61fc660c0b627.tar.bz2 rails-fc46c9b2207c62d4b029c2c891c61fc660c0b627.zip |
Added CDATA support to the XmlMini LibXML engine, adjusted whitespace handling to closer match that of the REXML engine, and added a LibXML engine test
Signed-off-by: Michael Koziarski <michael@koziarski.com>
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/lib/active_support/xml_mini/libxml.rb | 13 | ||||
-rw-r--r-- | activesupport/test/xml_mini/libxml_engine_test.rb | 194 |
2 files changed, 202 insertions, 5 deletions
diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index 2ae22c35fb..0f7ba1918b 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -13,8 +13,6 @@ module ActiveSupport data = StringIO.new(data || '') end - LibXML::XML.default_keep_blanks = false - char = data.getc if char.nil? {} @@ -44,9 +42,9 @@ module LibXML #:nodoc: # hash:: # Hash to merge the converted element into. def to_hash(hash={}) - if text? - raise LibXML::XML::Error if content.length >= LIB_XML_LIMIT - hash[CONTENT_ROOT] = content + if text? || cdata? + raise LibXML::XML::Error if hash[CONTENT_ROOT].to_s.length + content.length >= LIB_XML_LIMIT + hash[CONTENT_ROOT] = hash[CONTENT_ROOT].to_s + content else sub_hash = insert_name_into_hash(hash, name) attributes_to_hash(sub_hash) @@ -88,6 +86,11 @@ module LibXML #:nodoc: # Hash to merge the children into. def children_to_hash(hash={}) each { |child| child.to_hash(hash) } + + if hash.length > 1 && hash[CONTENT_ROOT].blank? + hash.delete(CONTENT_ROOT) + end + attributes_to_hash(hash) hash end diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb new file mode 100644 index 0000000000..900c8052d6 --- /dev/null +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -0,0 +1,194 @@ +require 'abstract_unit' +require 'active_support/xml_mini' +require 'active_support/core_ext/hash/conversions' + +begin + require 'libxml' +rescue LoadError + # Skip libxml tests +else + +class LibxmlEngineTest < Test::Unit::TestCase + include ActiveSupport + + def setup + @default_backend = XmlMini.backend + XmlMini.backend = 'LibXML' + + LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do + end + + def teardown + XmlMini.backend = @default_backend + end + + def test_exception_thrown_on_expansion_attack + assert_raise LibXML::XML::Error do + attack_xml = %{<?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE member [ + <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> + <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> + <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;"> + <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;"> + <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;"> + <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;"> + <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"> + ]> + <member> + &a; + </member> + } + Hash.from_xml(attack_xml) + end + end + + def test_setting_libxml_as_backend + XmlMini.backend = 'LibXML' + assert_equal XmlMini_LibXML, XmlMini.backend + end + + def test_blank_returns_empty_hash + assert_equal({}, XmlMini.parse(nil)) + assert_equal({}, XmlMini.parse('')) + end + + def test_array_type_makes_an_array + assert_equal_rexml(<<-eoxml) + <blog> + <posts type="array"> + <post>a post</post> + <post>another post</post> + </posts> + </blog> + eoxml + 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 + + def test_parse_from_io + io = StringIO.new(<<-eoxml) + <root> + good + <products> + hello everyone + </products> + morning + </root> + eoxml + XmlMini.parse(io) + end + + def test_children_with_simple_cdata + assert_equal_rexml(<<-eoxml) + <root> + <products> + <![CDATA[cdatablock]]> + </products> + </root> + eoxml + end + + def test_children_with_multiple_cdata + assert_equal_rexml(<<-eoxml) + <root> + <products> + <![CDATA[cdatablock1]]><![CDATA[cdatablock2]]> + </products> + </root> + eoxml + end + + def test_children_with_text_and_cdata + assert_equal_rexml(<<-eoxml) + <root> + <products> + hello <![CDATA[cdatablock]]> + morning + </products> + </root> + eoxml + end + + def test_children_with_blank_text + assert_equal_rexml(<<-eoxml) + <root> + <products> </products> + </root> + eoxml + end + + private + def assert_equal_rexml(xml) + hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) } + assert_equal(hash, XmlMini.parse(xml)) + end +end + +end |