multi_xml-0.5.5/0000755000004100000410000000000012250230401013550 5ustar www-datawww-datamulti_xml-0.5.5/Rakefile0000644000004100000410000000066112250230401015220 0ustar www-datawww-datarequire 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) task :test => :spec task :default => :spec namespace :doc do require 'yard' YARD::Rake::YardocTask.new do |task| task.files = ['lib/**/*.rb', '-', 'LICENSE.md'] task.options = [ '--no-private', '--protected', '--output-dir', 'doc/yard', '--markup', 'markdown', ] end end multi_xml-0.5.5/multi_xml.gemspec0000644000004100000410000000201712250230401017127 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'multi_xml/version' Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 1.0' spec.author = "Erik Michaels-Ober" spec.cert_chain = ['certs/sferik.pem'] spec.description = %q{Provides swappable XML backends utilizing LibXML, Nokogiri, Ox, or REXML.} spec.email = 'sferik@gmail.com' spec.files = %w(.yardopts CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile multi_xml.gemspec) spec.files += Dir.glob("lib/**/*.rb") spec.files += Dir.glob("spec/**/*") spec.homepage = 'https://github.com/sferik/multi_xml' spec.licenses = ['MIT'] spec.name = 'multi_xml' spec.require_paths = ['lib'] spec.required_rubygems_version = '>= 1.3.5' spec.signing_key = File.expand_path("~/.gem/private_key.pem") if $0 =~ /gem\z/ spec.summary = %q{A generic swappable back-end for XML parsing} spec.test_files = Dir.glob("spec/**/*") spec.version = MultiXml::VERSION end multi_xml-0.5.5/data.tar.gz.sig0000644000004100000410000000040012250230401016363 0ustar www-datawww-dataDX^hE wtM)ͦώ a-k_0(7 eW&X,V#75 3a ;R>׮&.":f<J %Q=')pΐ2$z5΢q`τ9<uy//ZOs'8n}1Eo>McCR>Q€NPu+P[2ԉQӽw>&Zmulti_xml-0.5.5/spec/0000755000004100000410000000000012250230401014502 5ustar www-datawww-datamulti_xml-0.5.5/spec/helper.rb0000644000004100000410000000050612250230401016307 0ustar www-datawww-datarequire 'simplecov' require 'coveralls' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter ] SimpleCov.start require 'multi_xml' require 'rspec' RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = :expect end end multi_xml-0.5.5/spec/parser_shared_example.rb0000644000004100000410000005160712250230401021375 0ustar www-datawww-datashared_examples_for "a parser" do |parser| before do begin MultiXml.parser = parser rescue LoadError pending "Parser #{parser} couldn't be loaded" end end describe ".parse" do context "a blank string" do before do @xml = '' end it "returns an empty Hash" do expect(MultiXml.parse(@xml)).to eq({}) end end context "a whitespace string" do before do @xml = ' ' end it "returns an empty Hash" do expect(MultiXml.parse(@xml)).to eq({}) end end context "an invalid XML document" do before do @xml = '' end it "raises MultiXml::ParseError" do expect{MultiXml.parse(@xml)}.to raise_error(MultiXml::ParseError) end end context "a valid XML document" do before do @xml = '' end it "parses correctly" do expect(MultiXml.parse(@xml)).to eq({'user' => nil}) end context "with CDATA" do before do @xml = '' end it "returns the correct CDATA" do expect(MultiXml.parse(@xml)['user']).to eq("Erik Michaels-Ober") end end context "element with the same inner element and attribute name" do before do @xml = "Smith" end it "returns nams as Array" do expect(MultiXml.parse(@xml)['user']['name']).to eq ['John', 'Smith'] end end context "with content" do before do @xml = 'Erik Michaels-Ober' end it "returns the correct content" do expect(MultiXml.parse(@xml)['user']).to eq("Erik Michaels-Ober") end end context "with an attribute" do before do @xml = '' end it "returns the correct attribute" do expect(MultiXml.parse(@xml)['user']['name']).to eq("Erik Michaels-Ober") end end context "with multiple attributes" do before do @xml = '' end it "returns the correct attributes" do expect(MultiXml.parse(@xml)['user']['name']).to eq("Erik Michaels-Ober") expect(MultiXml.parse(@xml)['user']['screen_name']).to eq("sferik") end end context "typecast management" do before do @xml = %Q{ Settings Test } end context "with :typecast_xml_value => true" do before do @setting = MultiXml.parse(@xml)["global_settings"]["group"]["setting"] end it { expect(@setting).to eq "" } end context "with :typecast_xml_value => false" do before do @setting = MultiXml.parse(@xml, :typecast_xml_value => false)["global_settings"]["group"]["setting"] end it { expect(@setting).to eq({"type"=>"string", "description"=>{"__content__"=>"Test"}}) } end end context "with :symbolize_keys => true" do before do @xml = 'Wynn Netherland' end it "symbolizes keys" do expect(MultiXml.parse(@xml, :symbolize_keys => true)).to eq({:users => {:user => [{:name => "Erik Michaels-Ober"}, {:name => "Wynn Netherland"}]}}) end end context "with an attribute type=\"boolean\"" do %w(true false).each do |boolean| context "when #{boolean}" do it "returns #{boolean}" do xml = "#{boolean}" expect(MultiXml.parse(xml)['tag']).to instance_eval("be_#{boolean}") end end end context "when 1" do before do @xml = '1' end it "returns true" do expect(MultiXml.parse(@xml)['tag']).to be_true end end context "when 0" do before do @xml = '0' end it "returns false" do expect(MultiXml.parse(@xml)['tag']).to be_false end end end context "with an attribute type=\"integer\"" do context "with a positive integer" do before do @xml = '1' end it "returns a Fixnum" do expect(MultiXml.parse(@xml)['tag']).to be_a(Fixnum) end it "returns a positive number" do expect(MultiXml.parse(@xml)['tag']).to be > 0 end it "returns the correct number" do expect(MultiXml.parse(@xml)['tag']).to eq(1) end end context "with a negative integer" do before do @xml = '-1' end it "returns a Fixnum" do expect(MultiXml.parse(@xml)['tag']).to be_a(Fixnum) end it "returns a negative number" do expect(MultiXml.parse(@xml)['tag']).to be < 0 end it "returns the correct number" do expect(MultiXml.parse(@xml)['tag']).to eq(-1) end end end context "with an attribute type=\"string\"" do before do @xml = '' end it "returns a String" do expect(MultiXml.parse(@xml)['tag']).to be_a(String) end it "returns the correct string" do expect(MultiXml.parse(@xml)['tag']).to eq("") end end context "with an attribute type=\"date\"" do before do @xml = '1970-01-01' end it "returns a Date" do expect(MultiXml.parse(@xml)['tag']).to be_a(Date) end it "returns the correct date" do expect(MultiXml.parse(@xml)['tag']).to eq(Date.parse('1970-01-01')) end end context "with an attribute type=\"datetime\"" do before do @xml = '1970-01-01 00:00' end it "returns a Time" do expect(MultiXml.parse(@xml)['tag']).to be_a(Time) end it "returns the correct time" do expect(MultiXml.parse(@xml)['tag']).to eq(Time.parse('1970-01-01 00:00')) end end context "with an attribute type=\"dateTime\"" do before do @xml = '1970-01-01 00:00' end it "returns a Time" do expect(MultiXml.parse(@xml)['tag']).to be_a(Time) end it "returns the correct time" do expect(MultiXml.parse(@xml)['tag']).to eq(Time.parse('1970-01-01 00:00')) end end context "with an attribute type=\"double\"" do before do @xml = '3.14159265358979' end it "returns a Float" do expect(MultiXml.parse(@xml)['tag']).to be_a(Float) end it "returns the correct number" do expect(MultiXml.parse(@xml)['tag']).to eq(3.14159265358979) end end context "with an attribute type=\"decimal\"" do before do @xml = '3.14159265358979' end it "returns a BigDecimal" do expect(MultiXml.parse(@xml)['tag']).to be_a(BigDecimal) end it "returns the correct number" do expect(MultiXml.parse(@xml)['tag']).to eq(3.14159265358979) end end context "with an attribute type=\"base64Binary\"" do before do @xml = 'aW1hZ2UucG5n' end it "returns a String" do expect(MultiXml.parse(@xml)['tag']).to be_a(String) end it "returns the correct string" do expect(MultiXml.parse(@xml)['tag']).to eq("image.png") end end context "with an attribute type=\"yaml\"" do before do @xml = "--- \n1: returns an integer\n:message: Have a nice day\narray: \n- has-dashes: true\n has_underscores: true\n" end it "raises MultiXML::DisallowedTypeError by default" do expect{ MultiXml.parse(@xml)['tag'] }.to raise_error(MultiXml::DisallowedTypeError) end it "returns the correctly parsed YAML when the type is allowed" do expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to eq({:message => "Have a nice day", 1 => "returns an integer", "array" => [{"has-dashes" => true, "has_underscores" => true}]}) end end context "with an attribute type=\"symbol\"" do before do @xml = "my_symbol" end it "raises MultiXML::DisallowedTypeError" do expect{ MultiXml.parse(@xml)['tag'] }.to raise_error(MultiXml::DisallowedTypeError) end it "returns the correctly parsed Symbol when the type is allowed" do expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to eq(:my_symbol) end end context "with an attribute type=\"file\"" do before do @xml = 'ZGF0YQ==' end it "returns a StringIO" do expect(MultiXml.parse(@xml)['tag']).to be_a(StringIO) end it "is decoded correctly" do expect(MultiXml.parse(@xml)['tag'].string).to eq('data') end it "has the correct file name" do expect(MultiXml.parse(@xml)['tag'].original_filename).to eq('data.txt') end it "has the correct content type" do expect(MultiXml.parse(@xml)['tag'].content_type).to eq('text/plain') end context "with missing name and content type" do before do @xml = 'ZGF0YQ==' end it "returns a StringIO" do expect(MultiXml.parse(@xml)['tag']).to be_a(StringIO) end it "is decoded correctly" do expect(MultiXml.parse(@xml)['tag'].string).to eq('data') end it "has the default file name" do expect(MultiXml.parse(@xml)['tag'].original_filename).to eq('untitled') end it "has the default content type" do expect(MultiXml.parse(@xml)['tag'].content_type).to eq('application/octet-stream') end end end context "with an attribute type=\"array\"" do before do @xml = 'Erik Michaels-OberWynn Netherland' end it "returns an Array" do expect(MultiXml.parse(@xml)['users']).to be_a(Array) end it "returns the correct array" do expect(MultiXml.parse(@xml)['users']).to eq(["Erik Michaels-Ober", "Wynn Netherland"]) end end context "with an attribute type=\"array\" in addition to other attributes" do before do @xml = 'Erik Michaels-OberWynn Netherland' end it "returns an Array" do expect(MultiXml.parse(@xml)['users']).to be_a(Array) end it "returns the correct array" do expect(MultiXml.parse(@xml)['users']).to eq(["Erik Michaels-Ober", "Wynn Netherland"]) end end context "with an attribute type=\"array\" containing only one item" do before do @xml = 'Erik Michaels-Ober' end it "returns an Array" do expect(MultiXml.parse(@xml)['users']).to be_a(Array) end it "returns the correct array" do expect(MultiXml.parse(@xml)['users']).to eq(["Erik Michaels-Ober"]) end end %w(integer boolean date datetime file).each do |type| context "with an empty attribute type=\"#{type}\"" do before do @xml = "" end it "returns nil" do expect(MultiXml.parse(@xml)['tag']).to be_nil end end end %w{yaml symbol}.each do |type| context "with an empty attribute type=\"#{type}\"" do before do @xml = "" end it "raises MultiXml::DisallowedTypeError by default" do expect{ MultiXml.parse(@xml)['tag']}.to raise_error(MultiXml::DisallowedTypeError) end it "returns nil when the type is allowed" do expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to be_nil end end end context "with an empty attribute type=\"array\"" do before do @xml = '' end it "returns an empty Array" do expect(MultiXml.parse(@xml)['tag']).to eq([]) end context "with whitespace" do before do @xml = ' ' end it "returns an empty Array" do expect(MultiXml.parse(@xml)['tag']).to eq([]) end end end context "with XML entities" do before do @xml_entities = { "<" => "<", ">" => ">", '"' => """, "'" => "'", "&" => "&" } end context "in content" do it "returns unescaped XML entities" do @xml_entities.each do |key, value| xml = "#{value}" expect(MultiXml.parse(xml)['tag']).to eq(key) end end end context "in attribute" do it "returns unescaped XML entities" do @xml_entities.each do |key, value| xml = "" expect(MultiXml.parse(xml)['tag']['attribute']).to eq(key) end end end end context "with dasherized tag" do before do @xml = '' end it "returns undasherize tag" do expect(MultiXml.parse(@xml).keys).to include('tag_1') end end context "with dasherized attribute" do before do @xml = '' end it "returns undasherize attribute" do expect(MultiXml.parse(@xml)['tag'].keys).to include('attribute_1') end end context "with children" do context "with attributes" do before do @xml = '' end it "returns the correct attributes" do expect(MultiXml.parse(@xml)['users']['user']['name']).to eq("Erik Michaels-Ober") end end context "with text" do before do @xml = 'Erik Michaels-Ober' end it "returns the correct text" do expect(MultiXml.parse(@xml)['user']['name']).to eq("Erik Michaels-Ober") end end context "with an unrecognized attribute type" do before do @xml = 'Erik Michaels-Ober' end it "passes through the type" do expect(MultiXml.parse(@xml)['user']['type']).to eq('admin') end end context "with attribute tags on content nodes" do context "non 'type' attributes" do before do @xml = <<-XML 123 0.123 XML @parsed_xml = MultiXml.parse(@xml) end it "adds the attributes to the value hash" do expect(@parsed_xml['options']['value'][0]['__content__']).to eq('123') expect(@parsed_xml['options']['value'][0]['currency']).to eq('USD') expect(@parsed_xml['options']['value'][1]['__content__']).to eq('0.123') expect(@parsed_xml['options']['value'][1]['number']).to eq('percent') end end context "unrecognized type attributes" do before do @xml = <<-XML 123 0.123 123 XML @parsed_xml = MultiXml.parse(@xml) end it "adds the attributes to the value hash passing through the type" do expect(@parsed_xml['options']['value'][0]['__content__']).to eq('123') expect(@parsed_xml['options']['value'][0]['type']).to eq('USD') expect(@parsed_xml['options']['value'][1]['__content__']).to eq('0.123') expect(@parsed_xml['options']['value'][1]['type']).to eq('percent') expect(@parsed_xml['options']['value'][2]['__content__']).to eq('123') expect(@parsed_xml['options']['value'][2]['currency']).to eq('USD') end end context "mixing attributes and non-attributes content nodes type attributes" do before do @xml = <<-XML 123 0.123 123 XML @parsed_xml = MultiXml.parse(@xml) end it "adds the attributes to the value hash passing through the type" do expect(@parsed_xml['options']['value'][0]['__content__']).to eq('123') expect(@parsed_xml['options']['value'][0]['type']).to eq('USD') expect(@parsed_xml['options']['value'][1]['__content__']).to eq('0.123') expect(@parsed_xml['options']['value'][1]['type']).to eq('percent') expect(@parsed_xml['options']['value'][2]).to eq('123') end end context "mixing recognized type attribute and non-type attributes on content nodes" do before do @xml = <<-XML 123 XML @parsed_xml = MultiXml.parse(@xml) end it "adds the the non-type attribute and remove the recognized type attribute and do the typecast" do expect(@parsed_xml['options']['value']['__content__']).to eq(123) expect(@parsed_xml['options']['value']['number']).to eq('USD') end end context "mixing unrecognized type attribute and non-type attributes on content nodes" do before do @xml = <<-XML 123 XML @parsed_xml = MultiXml.parse(@xml) end it "adds the the non-type attributes and type attribute to the value hash" do expect(@parsed_xml['options']['value']['__content__']).to eq('123') expect(@parsed_xml['options']['value']['number']).to eq('USD') expect(@parsed_xml['options']['value']['type']).to eq('currency') end end end context "with newlines and whitespace" do before do @xml = <<-XML Erik Michaels-Ober XML end it "parses correctly" do expect(MultiXml.parse(@xml)).to eq({"user" => {"name" => "Erik Michaels-Ober"}}) end end # Babies having babies context "with children" do before do @xml = '' end it "parses correctly" do expect(MultiXml.parse(@xml)).to eq({"users" => {"user" => {"name" => "Erik Michaels-Ober", "status" => {"text" => "Hello"}}}}) end end end context "with sibling children" do before do @xml = 'Erik Michaels-OberWynn Netherland' end it "returns an Array" do expect(MultiXml.parse(@xml)['users']['user']).to be_a(Array) end it "parses correctly" do expect(MultiXml.parse(@xml)).to eq({"users" => {"user" => ["Erik Michaels-Ober", "Wynn Netherland"]}}) end end end end end multi_xml-0.5.5/spec/speed.rb0000755000004100000410000000251212250230401016132 0ustar www-datawww-data#!/usr/bin/env ruby -wW1 $: << '.' $: << '../lib' if __FILE__ == $0 while (i = ARGV.index('-I')) x,path = ARGV.slice!(i, 2) $: << path end end require 'optparse' require 'stringio' require 'multi_xml' begin require 'libxml' rescue Exception => e end begin require 'nokogiri' rescue Exception => e end begin require 'ox' rescue Exception => e end $verbose = 0 $parsers = [] $iter = 10 opts = OptionParser.new opts.on("-v", "increase verbosity") { $verbose += 1 } opts.on("-p", "--parser [String]", String, "parser to test") { |p| $parsers = [p] } opts.on("-i", "--iterations [Int]", Integer, "iterations") { |i| $iter = i } opts.on("-h", "--help", "Show this display") { puts opts; Process.exit!(0) } files = opts.parse(ARGV) if $parsers.empty? $parsers << 'libxml' if defined?(::LibXML) $parsers << 'nokogiri' if defined?(::Nokogiri) $parsers << 'ox' if defined?(::Ox) end files.each do |filename| times = { } xml = File.read(filename) $parsers.each do |p| MultiXml.parser = p start = Time.now $iter.times do |i| io = StringIO.new(xml) MultiXml.parse(io) end dt = Time.now - start times[p] = Time.now - start end times.each do |p,t| puts "%8s took %0.3f seconds to parse %s %d times." % [p, t, filename, $iter] end end multi_xml-0.5.5/spec/multi_xml_spec.rb0000644000004100000410000000221212250230401020050 0ustar www-datawww-datarequire 'helper' require 'parser_shared_example' class MockDecoder; end describe "MultiXml" do context "Parsers" do it "picks a default parser" do expect(MultiXml.parser).to be_kind_of(Module) expect(MultiXml.parser).to respond_to(:parse) end it "defaults to the best available gem" do # Clear cache variable already set by previous tests MultiXml.send(:remove_instance_variable, :@parser) expect(MultiXml.parser.name).to eq('MultiXml::Parsers::Ox') end it "is settable via a symbol" do MultiXml.parser = :rexml expect(MultiXml.parser.name).to eq('MultiXml::Parsers::Rexml') end it "is settable via a class" do MultiXml.parser = MockDecoder expect(MultiXml.parser.name).to eq('MockDecoder') end end [['LibXML', 'libxml'], ['REXML', 'rexml/document'], ['Nokogiri', 'nokogiri'], ['Ox', 'ox']].each do |parser| begin require parser.last context "#{parser.first} parser" do it_behaves_like "a parser", parser.first end rescue LoadError => e puts "Tests not run for #{parser.first} due to a LoadError" end end end multi_xml-0.5.5/LICENSE.md0000644000004100000410000000205312250230401015154 0ustar www-datawww-dataCopyright (c) 2010-2013 Erik Michaels-Ober Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. multi_xml-0.5.5/lib/0000755000004100000410000000000012250230401014316 5ustar www-datawww-datamulti_xml-0.5.5/lib/multi_xml/0000755000004100000410000000000012250230401016330 5ustar www-datawww-datamulti_xml-0.5.5/lib/multi_xml/parsers/0000755000004100000410000000000012250230401020007 5ustar www-datawww-datamulti_xml-0.5.5/lib/multi_xml/parsers/libxml2_parser.rb0000644000004100000410000000365212250230401023267 0ustar www-datawww-datamodule MultiXml module Parsers module Libxml2Parser #:nodoc: # Convert XML document to hash # # node:: # The XML node object to convert to a hash. # # hash:: # Hash to merge the converted element into. def node_to_hash(node, hash={}) node_hash = {MultiXml::CONTENT_ROOT => ''} name = node_name(node) # Insert node hash into parent hash correctly. case hash[name] when Array then hash[name] << node_hash when Hash then hash[name] = [hash[name], node_hash] when nil then hash[name] = node_hash end # Handle child elements each_child(node) do |c| if c.element? node_to_hash(c, node_hash) elsif c.text? || c.cdata? node_hash[MultiXml::CONTENT_ROOT] << c.content end end # Remove content node if it is empty if node_hash[MultiXml::CONTENT_ROOT].strip.empty? node_hash.delete(MultiXml::CONTENT_ROOT) end # Handle attributes each_attr(node) do |a| key = node_name(a) node_hash[key] = if v = node_hash[key] [a.value, v] else a.value end end hash end # Parse an XML Document IO into a simple hash. # xml:: # XML Document IO to parse def parse(xml) raise NotImplementedError, "inheritor should define #{__method__}" end # :stopdoc: private def each_child(*args) raise NotImplementedError, "inheritor should define #{__method__}" end def each_attr(*args) raise NotImplementedError, "inheritor should define #{__method__}" end def node_name(*args) raise NotImplementedError, "inheritor should define #{__method__}" end end end end multi_xml-0.5.5/lib/multi_xml/parsers/libxml.rb0000644000004100000410000000106212250230401021622 0ustar www-datawww-datarequire 'libxml' unless defined?(LibXML) require 'multi_xml/parsers/libxml2_parser' module MultiXml module Parsers module Libxml #:nodoc: include Libxml2Parser extend self def parse_error() ::LibXML::XML::Error end def parse(xml) node_to_hash(LibXML::XML::Parser.io(xml).parse.root) end def each_child(node, &block) node.each_child(&block) end def each_attr(node, &block) node.each_attr(&block) end def node_name(node) node.name end end end end multi_xml-0.5.5/lib/multi_xml/parsers/ox.rb0000644000004100000410000000427612250230401020773 0ustar www-datawww-datarequire 'ox' unless defined?(Ox) # Each MultiXml parser is expected to parse an XML document into a Hash. The # conversion rules are: # # - Each document starts out as an empty Hash. # # - Reading an element created an entry in the parent Hash that has a key of # the element name and a value of a Hash with attributes as key value # pairs. Children are added as described by this rule. # # - Text and CDATE is stored in the parent element Hash with a key of # MultiXml::CONTENT_ROOT and a value of the text itself. # # - If a key already exists in the Hash then the value associated with the key # is converted to an Array with the old and new value in it. # # - Other elements such as the xml prolog, doctype, and comments are ignored. # module MultiXml module Parsers module Ox #:nodoc: extend self def parse_error Exception end def parse(io) handler = Handler.new ::Ox.sax_parse(handler, io, :convert_special => true) handler.doc end class Handler attr_accessor :stack def initialize() @stack = [] end def doc @stack[0] end def attr(name, value) unless @stack.empty? append(name, value) end end def text(value) append(MultiXml::CONTENT_ROOT, value) end def cdata(value) append(MultiXml::CONTENT_ROOT, value) end def start_element(name) if @stack.empty? @stack.push(Hash.new) end h = Hash.new append(name, h) @stack.push(h) end def end_element(name) @stack.pop() end def error(message, line, column) raise Exception.new("#{message} at #{line}:#{column}") end def append(key, value) key = key.to_s h = @stack.last if h.has_key?(key) v = h[key] if v.is_a?(Array) v << value else h[key] = [v, value] end else h[key] = value end end end # Handler end # Ox end # Parsers end # MultiXml multi_xml-0.5.5/lib/multi_xml/parsers/rexml.rb0000644000004100000410000000622012250230401021463 0ustar www-datawww-datarequire 'rexml/document' unless defined?(REXML::Document) module MultiXml module Parsers module Rexml #:nodoc: extend self def parse_error; ::REXML::ParseException; end # Parse an XML Document IO into a simple hash using REXML # # xml:: # XML Document IO to parse def parse(xml) doc = REXML::Document.new(xml) if doc.root merge_element!({}, doc.root) else raise REXML::ParseException, "The document #{doc.to_s.inspect} does not have a valid root" end end private # Convert an XML element and merge into the hash # # hash:: # Hash to merge the converted element into. # element:: # XML element to merge into hash def merge_element!(hash, element) merge!(hash, element.name, collapse(element)) end # Actually converts an XML document element into a data structure. # # element:: # The document element to be collapsed. def collapse(element) hash = get_attributes(element) if element.has_elements? element.each_element {|child| merge_element!(hash, child) } merge_texts!(hash, element) unless empty_content?(element) hash else merge_texts!(hash, element) end end # Merge all the texts of an element into the hash # # hash:: # Hash to add the converted element to. # element:: # XML element whose texts are to me merged into the hash def merge_texts!(hash, element) unless element.has_text? hash else # must use value to prevent double-escaping texts = '' element.texts.each { |t| texts << t.value } merge!(hash, MultiXml::CONTENT_ROOT, texts) end end # Adds a new key/value pair to an existing Hash. If the key to be added # already exists and the existing value associated with key is not # an Array, it will be wrapped in an Array. Then the new value is # appended to that Array. # # hash:: # Hash to add key/value pair to. # key:: # Key to be added. # value:: # Value to be associated with key. def merge!(hash, key, value) if hash.has_key?(key) if hash[key].instance_of?(Array) hash[key] << value else hash[key] = [hash[key], value] end elsif value.instance_of?(Array) hash[key] = [value] else hash[key] = value end hash end # Converts the attributes array of an XML element into a hash. # Returns an empty Hash if node has no attributes. # # element:: # XML element to extract attributes from. def get_attributes(element) attributes = {} element.attributes.each { |n,v| attributes[n] = v } attributes end # Determines if a document element has text content # # element:: # XML element to be checked. def empty_content?(element) element.texts.join.strip.empty? end end end end multi_xml-0.5.5/lib/multi_xml/parsers/nokogiri.rb0000644000004100000410000000122012250230401022150 0ustar www-datawww-datarequire 'nokogiri' unless defined?(Nokogiri) require 'multi_xml/parsers/libxml2_parser' module MultiXml module Parsers module Nokogiri #:nodoc: include Libxml2Parser extend self def parse_error() ::Nokogiri::XML::SyntaxError end def parse(xml) doc = ::Nokogiri::XML(xml) raise doc.errors.first if doc.errors.length > 0 node_to_hash(doc.root) end def each_child(node, &block) node.children.each(&block) end def each_attr(node, &block) node.attribute_nodes.each(&block) end def node_name(node) node.node_name end end end end multi_xml-0.5.5/lib/multi_xml/version.rb0000644000004100000410000000011312250230401020335 0ustar www-datawww-datamodule MultiXml VERSION = "0.5.5" unless defined?(MultiXML::VERSION) end multi_xml-0.5.5/lib/multi_xml.rb0000644000004100000410000002203312250230401016655 0ustar www-datawww-datarequire 'base64' require 'bigdecimal' require 'date' require 'stringio' require 'time' require 'yaml' module MultiXml class ParseError < StandardError; end class DisallowedTypeError < StandardError def initialize(type) super "Disallowed type attribute: #{type.inspect}" end end REQUIREMENT_MAP = [ ['ox', :ox], ['libxml', :libxml], ['nokogiri', :nokogiri], ['rexml/document', :rexml] ] unless defined?(REQUIREMENT_MAP) CONTENT_ROOT = '__content__'.freeze unless defined?(CONTENT_ROOT) unless defined?(PARSING) PARSING = { 'symbol' => Proc.new{|symbol| symbol.to_sym}, 'date' => Proc.new{|date| Date.parse(date)}, 'datetime' => Proc.new{|time| Time.parse(time).utc rescue DateTime.parse(time).utc}, 'integer' => Proc.new{|integer| integer.to_i}, 'float' => Proc.new{|float| float.to_f}, 'decimal' => Proc.new{|number| BigDecimal(number)}, 'boolean' => Proc.new{|boolean| !%w(0 false).include?(boolean.strip)}, 'string' => Proc.new{|string| string.to_s}, 'yaml' => Proc.new{|yaml| YAML::load(yaml) rescue yaml}, 'base64Binary' => Proc.new{|binary| ::Base64.decode64(binary)}, 'binary' => Proc.new{|binary, entity| parse_binary(binary, entity)}, 'file' => Proc.new{|file, entity| parse_file(file, entity)}, } PARSING.update( 'double' => PARSING['float'], 'dateTime' => PARSING['datetime'] ) end TYPE_NAMES = { 'Symbol' => 'symbol', 'Fixnum' => 'integer', 'Bignum' => 'integer', 'BigDecimal' => 'decimal', 'Float' => 'float', 'TrueClass' => 'boolean', 'FalseClass' => 'boolean', 'Date' => 'date', 'DateTime' => 'datetime', 'Time' => 'datetime', 'Array' => 'array', 'Hash' => 'hash' } unless defined?(TYPE_NAMES) DISALLOWED_XML_TYPES = %w(symbol yaml) DEFAULT_OPTIONS = { :typecast_xml_value => true, :disallowed_types => DISALLOWED_XML_TYPES, :symbolize_keys => false } class << self # Get the current parser class. def parser return @parser if defined?(@parser) self.parser = self.default_parser @parser end # The default parser based on what you currently # have loaded and installed. First checks to see # if any parsers are already loaded, then checks # to see which are installed if none are loaded. def default_parser return :ox if defined?(::Ox) return :libxml if defined?(::LibXML) return :nokogiri if defined?(::Nokogiri) REQUIREMENT_MAP.each do |library, parser| begin require library return parser rescue LoadError next end end end # Set the XML parser utilizing a symbol, string, or class. # Supported by default are: # # * :libxml # * :nokogiri # * :ox # * :rexml def parser=(new_parser) case new_parser when String, Symbol require "multi_xml/parsers/#{new_parser.to_s.downcase}" @parser = MultiXml::Parsers.const_get("#{new_parser.to_s.split('_').map{|s| s.capitalize}.join('')}") when Class, Module @parser = new_parser else raise "Did not recognize your parser specification. Please specify either a symbol or a class." end end # Parse an XML string or IO into Ruby. # # Options # # :symbolize_keys :: If true, will use symbols instead of strings for the keys. # # :disallowed_types :: Types to disallow from being typecasted. Defaults to `['yaml', 'symbol']`. Use `[]` to allow all types. # # :typecast_xml_value :: If true, won't typecast values for parsed document def parse(xml, options={}) xml ||= '' options = DEFAULT_OPTIONS.merge(options) xml.strip! if xml.respond_to?(:strip!) begin xml = StringIO.new(xml) unless xml.respond_to?(:read) char = xml.getc return {} if char.nil? xml.ungetc(char) hash = undasherize_keys(parser.parse(xml) || {}) hash = options[:typecast_xml_value] ? typecast_xml_value(hash, options[:disallowed_types]) : hash rescue DisallowedTypeError raise rescue parser.parse_error => error raise ParseError, error.message, error.backtrace end hash = symbolize_keys(hash) if options[:symbolize_keys] hash end # This module decorates files with the original_filename # and content_type methods. module FileLike #:nodoc: attr_writer :original_filename, :content_type def original_filename @original_filename || 'untitled' end def content_type @content_type || 'application/octet-stream' end end private # TODO: Add support for other encodings def parse_binary(binary, entity) #:nodoc: case entity['encoding'] when 'base64' Base64.decode64(binary) else binary end end def parse_file(file, entity) f = StringIO.new(Base64.decode64(file)) f.extend(FileLike) f.original_filename = entity['name'] f.content_type = entity['content_type'] f end def symbolize_keys(params) case params when Hash params.inject({}) do |result, (key, value)| result.merge(key.to_sym => symbolize_keys(value)) end when Array params.map{|value| symbolize_keys(value)} else params end end def undasherize_keys(params) case params when Hash params.inject({}) do |hash, (key, value)| hash[key.to_s.tr('-', '_')] = undasherize_keys(value) hash end when Array params.map{|value| undasherize_keys(value)} else params end end def typecast_xml_value(value, disallowed_types=nil) disallowed_types ||= DISALLOWED_XML_TYPES case value when Hash if value.include?('type') && !value['type'].is_a?(Hash) && disallowed_types.include?(value['type']) raise DisallowedTypeError, value['type'] end if value['type'] == 'array' # this commented-out suggestion helps to avoid the multiple attribute # problem, but it breaks when there is only one item in the array. # # from: https://github.com/jnunemaker/httparty/issues/102 # # _, entries = value.detect { |k, v| k != 'type' && v.is_a?(Array) } # This attempt fails to consider the order that the detect method # retrieves the entries. #_, entries = value.detect {|key, _| key != 'type'} # This approach ignores attribute entries that are not convertable # to an Array which allows attributes to be ignored. _, entries = value.detect {|k, v| k != 'type' && (v.is_a?(Array) || v.is_a?(Hash)) } if entries.nil? || (entries.is_a?(String) && entries.strip.empty?) [] else case entries when Array entries.map {|entry| typecast_xml_value(entry, disallowed_types)} when Hash [typecast_xml_value(entries, disallowed_types)] else raise "can't typecast #{entries.class.name}: #{entries.inspect}" end end elsif value.has_key?(CONTENT_ROOT) content = value[CONTENT_ROOT] if block = PARSING[value['type']] if block.arity == 1 value.delete('type') if PARSING[value['type']] if value.keys.size > 1 value[CONTENT_ROOT] = block.call(content) value else block.call(content) end else block.call(content, value) end else value.keys.size > 1 ? value : content end elsif value['type'] == 'string' && value['nil'] != 'true' '' # blank or nil parsed values are represented by nil elsif value.empty? || value['nil'] == 'true' nil # If the type is the only element which makes it then # this still makes the value nil, except if type is # a XML node(where type['value'] is a Hash) elsif value['type'] && value.size == 1 && !value['type'].is_a?(Hash) nil else xml_value = value.inject({}) do |hash, (k, v)| hash[k] = typecast_xml_value(v, disallowed_types) hash end # Turn {:files => {:file => #} into {:files => #} so it is compatible with # how multipart uploaded files from HTML appear xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value end when Array value.map!{|i| typecast_xml_value(i, disallowed_types)} value.length > 1 ? value : value.first when String value else raise "can't typecast #{value.class.name}: #{value.inspect}" end end end end multi_xml-0.5.5/metadata.yml0000644000004100000410000000675112250230401016064 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: multi_xml version: !ruby/object:Gem::Version version: 0.5.5 prerelease: platform: ruby authors: - Erik Michaels-Ober autorequire: bindir: bin cert_chain: - !binary |- LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURMakNDQWhhZ0F3SUJB Z0lCQURBTkJna3Foa2lHOXcwQkFRVUZBREE5TVE4d0RRWURWUVFEREFaelpt VnkKYVdzeEZUQVRCZ29Ka2lhSmsvSXNaQUVaRmdWbmJXRnBiREVUTUJFR0Nn bVNKb21UOGl4a0FSa1dBMk52YlRBZQpGdzB4TXpBeU1ETXhNREF5TWpkYUZ3 MHhOREF5TURNeE1EQXlNamRhTUQweER6QU5CZ05WQkFNTUJuTm1aWEpwCmF6 RVZNQk1HQ2dtU0pvbVQ4aXhrQVJrV0JXZHRZV2xzTVJNd0VRWUtDWkltaVpQ eUxHUUJHUllEWTI5dE1JSUIKSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4 QU1JSUJDZ0tDQVFFQWwweDVkeDh1S3hpN1Rrckl1eUJVVEpWQgp2MW85M25V QjlqL3k0TTk2Z1Yycll3QWNpMUpQQnNlTmQ2RnliempvM1lHdUhsN0VRSHVT SE5hZjFwMmx4ZXcvCnk2MEpYSUpCQmdQY0RLL0tDUDROVUhvZm0wamZvWUQr SDV1TkpmSENOcTcvWnNUeE90RTNSYTkyczBCQ01UcG0Kd0JNTWxXUjVNdGRF aElZdUJPNFhobmVqWWdIMEwvN0JMMmx5bW50Vm5zci9hZ2RRb29qUUNOMUlR bXNSSnZyUgpkdVpSTzN0WnZvSW8xcEJjNEpFZWhEdXFDZXlCZ1BMT3FNb0t0 UWxvbGQxVFFzMWtXVUJLN0tXTUZFaEtDL0tnCnp5ektSSFFvOXlEWXdPdllu Z29CTFkrVC9sd0NUNGR5c3NkaHpSYmZueEFoYUt1NFNBc3NJd2FDMDF5Vm93 SUQKQVFBQm96a3dOekFKQmdOVkhSTUVBakFBTUIwR0ExVWREZ1FXQkJTMHJ1 RGZSYWs1Y2kxT3BETlgvWmRERWtJcwppVEFMQmdOVkhROEVCQU1DQkxBd0RR WUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFISFNNcy9NUDBzT2FMa0V2NEpvCnp2 a20zcW41QTZ0MHZhSHg3NzRjbWVqeU1VKzV3eVN4UmV6c3BMN1VMaDlOZXVL Mk9oVStPZTNUcHFyQWc1VEsKUjhHUUlMblZ1MkZlbUdBNnNBa1BEbGNQdGdB NmllSTE5UFpPRjZIVkxtYy9JRC9kUC9OZ1pXV3pFZXFRS21jSwoyK0hNK1NF RURoWmtTY1lla3c0Wk9lMTY0WnRaRzgxNm9BdjV4MHBHaXRTSWt1bVVwN1Y4 aUVaLzZlaHI3WTllClhPZzRlZXVuNUwvSmptakFSb1cya05kdmtSRDNjMkVl U0xxV3ZRUnNCbHlwSGZoczZKSnVMbHlaUEdoVTNSL3YKU2YzbFZLcEJDV2dS cEdUdnk0NVhWcEIrNTl5MzNQSm1FdVExUFRFT1l2UXlhbzlVS01BQWFBTi83 cVdRdGpsMApobHc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K date: 2013-08-06 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '1.0' description: Provides swappable XML backends utilizing LibXML, Nokogiri, Ox, or REXML. email: sferik@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - .yardopts - CHANGELOG.md - CONTRIBUTING.md - LICENSE.md - README.md - Rakefile - multi_xml.gemspec - lib/multi_xml/parsers/libxml.rb - lib/multi_xml/parsers/libxml2_parser.rb - lib/multi_xml/parsers/nokogiri.rb - lib/multi_xml/parsers/ox.rb - lib/multi_xml/parsers/rexml.rb - lib/multi_xml/version.rb - lib/multi_xml.rb - spec/helper.rb - spec/multi_xml_spec.rb - spec/parser_shared_example.rb - spec/speed.rb homepage: https://github.com/sferik/multi_xml licenses: - MIT post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.3.5 requirements: [] rubyforge_project: rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: A generic swappable back-end for XML parsing test_files: - spec/helper.rb - spec/multi_xml_spec.rb - spec/parser_shared_example.rb - spec/speed.rb has_rdoc: multi_xml-0.5.5/.yardopts0000644000004100000410000000013712250230401015417 0ustar www-datawww-data--no-private --protected --markup markdown - CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md multi_xml-0.5.5/CONTRIBUTING.md0000644000004100000410000000362512250230401016007 0ustar www-datawww-data## Contributing In the spirit of [free software][free-sw] , **everyone** is encouraged to help improve this project. [free-sw]: http://www.fsf.org/licensing/essays/free-sw.html Here are some ways *you* can contribute: * by using alpha, beta, and prerelease versions * by reporting bugs * by suggesting new features * by writing or editing documentation * by writing specifications * by writing code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace) * by refactoring code * by resolving [issues][] * by reviewing patches [issues]: https://github.com/sferik/multi_xml/issues ## Submitting an Issue We use the [GitHub issue tracker][issues] to track bugs and features. Before submitting a bug report or feature request, check to make sure it hasn't already been submitted. When submitting a bug report, please include a [Gist][] that includes a stack trace and any details that may be necessary to reproduce the bug, including your gem version, Ruby version, and operating system. Ideally, a bug report should include a pull request with failing specs. [gist]: https://gist.github.com/ ## Submitting a Pull Request 1. [Fork the repository.][fork] 2. [Create a topic branch.][branch] 3. Add specs for your unimplemented feature or bug fix. 4. Run `bundle exec rake spec`. If your specs pass, return to step 3. 5. Implement your feature or bug fix. 6. Run `bundle exec rake spec`. If your specs fail, return to step 5. 7. Run `open coverage/index.html`. If your changes are not completely covered by your tests, return to step 3. 8. Add documentation for your feature or bug fix. 9. Run `bundle exec rake doc:yard`. If your changes are not 100% documented, go back to step 8. 10. Add, commit, and push your changes. 11. [Submit a pull request.][pr] [fork]: http://help.github.com/fork-a-repo/ [branch]: http://learn.github.com/p/branching.html [pr]: http://help.github.com/send-pull-requests/ multi_xml-0.5.5/CHANGELOG.md0000644000004100000410000001011712250230401015361 0ustar www-datawww-data0.5.5 ----- * [Fix symbolize_keys function](https://github.com/sferik/multi_xml/commit/a4cae3aeb690999287cd30206399abaa5ce1ae81) * [Fix Nokogiri parser for the same attr and inner element name](https://github.com/sferik/multi_xml/commit/a28ed86e2d7826b2edeed98552736b4c7ca52726) 0.5.4 ----- * [Add option to not cast parsed values](https://github.com/sferik/multi_xml/commit/44fc05fbcfd60cc8b555b75212471fab29fa8cd0) * [Use message instead of to_s](https://github.com/sferik/multi_xml/commit/b06f0114434ffe1957dd7bc2712cb5b76c1b45fe) 0.5.3 ----- * [Add cryptographic signature](https://github.com/sferik/multi_xml/commit/f39f0c74308090737816c622dbb7d7aa28c646c0) 0.5.2 ----- * [Remove ability to parse symbols and YAML](https://github.com/sferik/multi_xml/pull/34) 0.5.1 ----- * [Revert "Reset @@parser in between specs"](https://github.com/sferik/multi_xml/issues/28) 0.5.0 ----- * [Reset @@parser in between specs](https://github.com/sferik/multi_xml/commit/b562bed265918b43ac1c4c638ae3a7ffe95ecd83) * [Add attributes being passed through on content nodes](https://github.com/sferik/multi_xml/commit/631a8bb3c2253db0024f77f47c16d5a53b8128fd) 0.4.4 ----- * [Fix regression in MultiXml.parse](https://github.com/sferik/multi_xml/commit/45ae597d9a35cbd89cc7f5518c85bac30199fc06) 0.4.3 ----- * [Make parser a class variable](https://github.com/sferik/multi_xml/commit/6804ffc8680ed6466c66f2472f5e016c412c2c24) * [Add TYPE_NAMES constant](https://github.com/sferik/multi_xml/commit/72a21f2e86c8e3ac9689cee5f3a62102cfb98028) 0.4.2 ----- * [Fix bug in dealing with xml element attributes for both REXML and Ox](https://github.com/sferik/multi_xml/commit/ba3c1ac427ff0268abaf8186fb4bd81100c99559) * [Make Ox the preferred XML parser](https://github.com/sferik/multi_xml/commit/0a718d740c30fba426f300a929cda9ee8250d238) 0.4.1 ----- * [Use the SAX like parser with Ox](https://github.com/sferik/multi_xml/commit/d289d42817a32e48483c00d5361c76fbea62a166) 0.4.0 ----- * [Add support for Ox](https://github.com/sferik/multi_xml/pull/14) 0.3.0 ----- * [Remove core class monkeypatches](https://github.com/sferik/multi_xml/commit/f7cc3ce4d2924c0e0adc6935d1fba5ec79282938) * [Sort out some class / singleton class issues](https://github.com/sferik/multi_xml/commit/a5dac06bcf658facaaf7afa295f1291c7be15a44) * [Have parsers refer to toplevel CONTENT_ROOT instead of defining it](https://github.com/sferik/multi_xml/commit/94e6fa49e69b2a2467a0e6d3558f7d9815cae47e) * [Move redundant input sanitizing to top-level](https://github.com/sferik/multi_xml/commit/4874148214dbbd2e5a4b877734e2519af42d6132) * [Refactor libxml and nokogiri parsers to inherit from a common ancestor](https://github.com/sferik/multi_xml/commit/e0fdffcbfe641b6aaa3952ffa0570a893de325c2) 0.2.2 ----- * [Respect the global load path](https://github.com/sferik/multi_xml/commit/68eb3011b37f0e0222bb842abd2a78e1285a97c1) 0.2.1 ----- * [Add BlueCloth gem as development dependency for Markdown formatting](https://github.com/sferik/multi_xml/commit/18195cd1789176709f68f0d7f8df7fc944fe4d24) * [Replace BlueCloth with Maruku for JRuby compatibility](https://github.com/sferik/multi_xml/commit/bad5516a5ec5e7ef7fc5a35c411721522357fa19) 0.2.0 ----- * [Do not automatically load all library files](https://github.com/sferik/multi_xml/commit/dbd0447e062e8930118573c5453150e9371e5955) 0.1.4 ----- * [Preserve backtrace when catching/throwing exceptions](https://github.com/sferik/multi_xml/commit/7475ee90201c2701fddd524082832d16ca62552d) 0.1.3 ----- * [Common error handling for all parsers](https://github.com/sferik/multi_xml/commit/5357c28eddc14e921fd1be1f445db602a8dddaf2) 0.1.2 ----- * [Make wrap an Array class method](https://github.com/sferik/multi_xml/commit/28307b69bd1d9460353c861466e425c2afadcf56) 0.1.1 ----- * [Fix parsing for strings that contain newlines](https://github.com/sferik/multi_xml/commit/68087a4ce50b5d63cfa60d6f1fcbc2f6d689e43f) 0.1.0 ----- * [Add support for LibXML and Nokogiri](https://github.com/sferik/multi_xml/commit/856bb17fce66601e0b3d3eb3b64dbeb25aed3bca) 0.0.1 ----- * [REXML support](https://github.com/sferik/multi_xml/commit/2a848384a7b90fb3e26b5a8d4dc3fa3e3f2db5fc) multi_xml-0.5.5/metadata.gz.sig0000644000004100000410000000040012250230401016445 0ustar www-datawww-data; m+azO1Zvv.[DpmQG H=.}& x(s6E i1Mxxp+&wl Q ԼE&ȃ>tW#IJQrȠ+j Z1ңt3q@rwTP|v .)m $!7 p}\uAM*!uWB=5|8؜n WB+multi_xml-0.5.5/README.md0000644000004100000410000000716312250230401015036 0ustar www-datawww-data# MultiXML [![Gem Version](https://badge.fury.io/rb/multi_xml.png)][gem] [![Build Status](https://secure.travis-ci.org/sferik/multi_xml.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/sferik/multi_xml.png?travis)][gemnasium] [![Code Climate](https://codeclimate.com/github/sferik/multi_xml.png)][codeclimate] [![Coverage Status](https://coveralls.io/repos/sferik/multi_xml/badge.png?branch=master)][coveralls] [gem]: https://rubygems.org/gems/multi_xml [travis]: http://travis-ci.org/sferik/multi_xml [gemnasium]: https://gemnasium.com/sferik/multi_xml [codeclimate]: https://codeclimate.com/github/sferik/multi_xml [coveralls]: https://coveralls.io/r/sferik/multi_xml A generic swappable back-end for XML parsing ## Installation gem install multi_xml To ensure the code you're installing hasn't been tampered with, it's recommended that you verify the signature. To do this, you need to add my public key as a trusted certificate (you only need to do this once): gem cert --add <(curl -Ls https://raw.github.com/sferik/multi_xml/master/certs/sferik.pem) Then, install the gem with the high security trust policy: gem install multi_xml -P HighSecurity ## Documentation [http://rdoc.info/gems/multi_xml][documentation] [documentation]: http://rdoc.info/gems/multi_xml ## Usage Examples Lots of Ruby libraries utilize XML parsing in some form, and everyone has their favorite XML library. In order to best support multiple XML parsers and libraries, `multi_xml` is a general-purpose swappable XML backend library. You use it like so: ```ruby require 'multi_xml' MultiXml.parser = :ox MultiXml.parser = MultiXml::Parsers::Ox # Same as above MultiXml.parse('This is the contents') # Parsed using Ox MultiXml.parser = :libxml MultiXml.parser = MultiXml::Parsers::Libxml # Same as above MultiXml.parse('This is the contents') # Parsed using LibXML MultiXml.parser = :nokogiri MultiXml.parser = MultiXml::Parsers::Nokogiri # Same as above MultiXml.parse('This is the contents') # Parsed using Nokogiri MultiXml.parser = :rexml MultiXml.parser = MultiXml::Parsers::Rexml # Same as above MultiXml.parse('This is the contents') # Parsed using REXML ``` The `parser` setter takes either a symbol or a class (to allow for custom XML parsers) that responds to `.parse` at the class level. MultiXML tries to have intelligent defaulting. That is, if you have any of the supported parsers already loaded, it will utilize them before attempting to load any. When loading, libraries are ordered by speed: first Ox, then LibXML, then Nokogiri, and finally REXML. ## Supported Ruby Versions This library aims to support and is [tested against][travis] the following Ruby implementations: * Ruby 1.8.7 * Ruby 1.9.2 * Ruby 1.9.3 * Ruby 2.0.0 If something doesn't work on one of these interpreters, it's a bug. This library may inadvertently work (or seem to work) on other Ruby implementations, however support will only be provided for the versions listed above. If you would like this library to support another Ruby version, you may volunteer to be a maintainer. Being a maintainer entails making sure all tests run and pass on that implementation. When something breaks on your implementation, you will be responsible for providing patches in a timely fashion. If critical issues for a particular implementation exist at the time of a major release, support for that Ruby version may be dropped. ## Inspiration MultiXML was inspired by [MultiJSON][]. [multijson]: https://github.com/intridea/multi_json/ ## Copyright Copyright (c) 2010-2013 Erik Michaels-Ober. See [LICENSE][] for details. [license]: LICENSE.md