Skip to content

Commit

Permalink
Add support for parsing XML and JSON from an IO as well as a string [#…
Browse files Browse the repository at this point in the history
…2659 state:resolved]

Signed-off-by: Joshua Peek <josh@joshpeek.com>
  • Loading branch information
brianmario authored and josh committed May 17, 2009
1 parent 344ee68 commit 53dda29
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 30 deletions.
8 changes: 3 additions & 5 deletions actionpack/lib/action_dispatch/middleware/params_parser.rb
Expand Up @@ -32,16 +32,14 @@ def parse_formatted_parameters(env)
when Proc
strategy.call(request.raw_post)
when :xml_simple, :xml_node
body = request.raw_post
body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
when :yaml
YAML.load(request.raw_post)
when :json
body = request.raw_post
if body.blank?
if request.body.size == 0
{}
else
data = ActiveSupport::JSON.decode(body)
data = ActiveSupport::JSON.decode(request.body)
data = {:_json => data} unless data.is_a?(Hash)
data.with_indifferent_access
end
Expand Down
5 changes: 4 additions & 1 deletion activesupport/lib/active_support/json/backends/jsongem.rb
Expand Up @@ -6,8 +6,11 @@ module Backends
module JSONGem
extend self

# Converts a JSON string into a Ruby object.
# Parses a JSON string or IO and convert it into an object
def decode(json)
if json.respond_to?(:read)
json = json.read
end
data = ::JSON.parse(json)
if ActiveSupport.parse_json_times
convert_dates_from(data)
Expand Down
5 changes: 4 additions & 1 deletion activesupport/lib/active_support/json/backends/yaml.rb
Expand Up @@ -9,8 +9,11 @@ module Backends
module Yaml
extend self

# Converts a JSON string into a Ruby object.
# Parses a JSON string or IO and converts it into an object
def decode(json)
if json.respond_to?(:read)
json = json.read
end
YAML.load(convert_json_to_yaml(json))
rescue ArgumentError => e
raise ParseError, "Invalid JSON string"
Expand Down
16 changes: 10 additions & 6 deletions activesupport/lib/active_support/xml_mini/jdom.rb
Expand Up @@ -24,15 +24,19 @@ module XmlMini_JDOM #:nodoc:
node_type_map = {}
NODE_TYPE_NAMES.each { |type| node_type_map[Node.send(type)] = type }

# Parse an XML Document string into a simple hash using Java's jdom.
# string::
# XML Document string to parse
def parse(string)
if string.blank?
# Parse an XML Document string or IO into a simple hash using Java's jdom.
# data::
# XML Document string or IO to parse
def parse(data)
if data.respond_to?(:read)
data = data.read
end

if data.blank?
{}
else
@dbf = DocumentBuilderFactory.new_instance
xml_string_reader = StringReader.new(string)
xml_string_reader = StringReader.new(data)
xml_input_source = InputSource.new(xml_string_reader)
doc = @dbf.new_document_builder.parse(xml_input_source)
merge_element!({}, doc.document_element)
Expand Down
16 changes: 10 additions & 6 deletions activesupport/lib/active_support/xml_mini/libxml.rb
Expand Up @@ -5,16 +5,20 @@ module ActiveSupport
module XmlMini_LibXML #:nodoc:
extend self

# Parse an XML Document string into a simple hash using libxml.
# string::
# XML Document string to parse
def parse(string)
# Parse an XML Document string or IO into a simple hash using libxml.
# data::
# XML Document string or IO to parse
def parse(data)
if data.respond_to?(:read)
data = data.read
end

LibXML::XML.default_keep_blanks = false

if string.blank?
if data.blank?
{}
else
LibXML::XML::Parser.string(string.strip).parse.to_hash
LibXML::XML::Parser.string(data.strip).parse.to_hash
end
end

Expand Down
16 changes: 10 additions & 6 deletions activesupport/lib/active_support/xml_mini/nokogiri.rb
Expand Up @@ -5,14 +5,18 @@ 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)
if string.blank?
# Parse an XML Document string or IO into a simple hash using libxml / nokogiri.
# data::
# XML Document string or IO to parse
def parse(data)
if data.respond_to?(:read)
data = data.read
end

if data.blank?
{}
else
doc = Nokogiri::XML(string)
doc = Nokogiri::XML(data)
raise doc.errors.first if doc.errors.length > 0
doc.to_hash
end
Expand Down
14 changes: 9 additions & 5 deletions activesupport/lib/active_support/xml_mini/rexml.rb
Expand Up @@ -7,16 +7,20 @@ module XmlMini_REXML #:nodoc:

CONTENT_KEY = '__content__'.freeze

# Parse an XML Document string into a simple hash
# Parse an XML Document string or IO into a simple hash
#
# Same as XmlSimple::xml_in but doesn't shoot itself in the foot,
# and uses the defaults from ActiveSupport
#
# string::
# XML Document string to parse
def parse(string)
# data::
# XML Document string or IO to parse
def parse(data)
if data.respond_to?(:read)
data = data.read
end

require 'rexml/document' unless defined?(REXML::Document)
doc = REXML::Document.new(string)
doc = REXML::Document.new(data)
merge_element!({}, doc.root)
end

Expand Down
13 changes: 13 additions & 0 deletions activesupport/test/xml_mini/nokogiri_engine_test.rb
Expand Up @@ -148,6 +148,19 @@ def test_children_with_non_adjacent_text
eoxml
end

def test_parse_from_io
io = StringIO.new(<<-eoxml)
<root>
good
<products>
hello everyone
</products>
morning
</root>
eoxml
XmlMini.parse(io)
end

private
def assert_equal_rexml(xml)
hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) }
Expand Down
14 changes: 14 additions & 0 deletions activesupport/test/xml_mini/rexml_engine_test.rb
Expand Up @@ -12,4 +12,18 @@ def test_set_rexml_as_backend
XmlMini.backend = 'REXML'
assert_equal XmlMini_REXML, XmlMini.backend
end

def test_parse_from_io
XmlMini.backend = 'REXML'
io = StringIO.new(<<-eoxml)
<root>
good
<products>
hello everyone
</products>
morning
</root>
eoxml
XmlMini.parse(io)
end
end

1 comment on commit 53dda29

@brianmario
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!
Now, what was the reason you removed the yajl-ruby JSON backend and updated JSON test?

I probably should have noted somewhere that the JSON test and yajl.rb backend were originally written by Rick Olson, and I made modifications to support the ability to be passed an IO.

Please sign in to comment.