libXML for Active Resource 2.0
Posted by Bart ten Brinke Mon, 25 Feb 2008 08:19:39 GMT
I received an email from Stevie Clifton today, asking about our libXML patch for rails 2.0. As we have been running 2.0 for quite some time now, I never realised I forgot to post the new overrides.
The file below goes into /config/initializers/libxml.rb
# This is actally a fix for activeresource as it
# will behave incorrectly when it encounters
# Complex xml files. This override fixes this,
# but it should be submitted to rails trunk.
module ActiveResource
module Formats
module XmlFormat
private
def from_xml_data(data)
if data.is_a?(Hash) && data.keys.size == 1
from_xml_data(data.values.first)
else
data
end
end
end
end
end
module Nedap #:nodoc:
module Hash #:nodoc:
module Conversions
def self.included(klass)
require 'xml/libxml'
klass.extend(ClassMethods)
end
module ClassMethods
# Hash from_xml mixin that uses libxml.
# This ensures a 20x speed increase
# Compared to libxml. Plus it is less ugly.
def from_xml(xml)
result = XML::Parser.string(xml).parse
return { result.root.name.to_s => xml_node_to_hash(result.root)}
end
def xml_node_to_hash(node)
# If we are at the root of the document, start the hash
if node.element?
if node.children?
result_hash = {}
node.each_child do |child|
result = xml_node_to_hash(child)
if child.name == "text"
if !child.next? and !child.prev?
return result
end
elsif result_hash[child.name]
if result_hash[child.name].is_a?(Object::Array)
result_hash[child.name] << result
else
result_hash[child.name] = [result_hash[child.name]] << result
end
else
result_hash[child.name] = result
end
end
return result_hash
else
return nil
end
else
return node.content.to_s
end
end
end
end
end
end
Hash.send :include, Nedap::Hash::Conversions
There you go. You now have a blazingly fast active resource! If you want some more bang out of your resource, add the following mixins to the initializer too:
# Add inflate to NET class (zLib support)
module Net
class HTTPResponse
def inflate!
require 'zlib'
@body = Zlib::Inflate.inflate(@body)
end
end
end
# Increase timeout and buffersize for big XML files
module Net
class BufferedIO
def rbuf_fill
timeout(3000) {
@rbuf << @io.sysread(32768)
}
end
end
end
