diff --git a/Gemfile b/Gemfile index e882397..96b856d 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ gemspec group :development do gem "bundler" gem "libxml-ruby", platforms: [:ruby, :jruby] + gem "nokogiri", platforms: [:ruby, :jruby] gem "rake" gem "test-unit" end diff --git a/lib/xmlrpc.rb b/lib/xmlrpc.rb index 367b79a..a961ebf 100644 --- a/lib/xmlrpc.rb +++ b/lib/xmlrpc.rb @@ -59,9 +59,12 @@ # * libxml (LibXMLStreamParser) # * Compiled # * See https://rubygems.org/gems/libxml-ruby/ +# * nokogiri (NokogiriStreamParser) +# * Compiled +# * See https://nokogiri.org # # * General -# * possible to choose between XMLParser module (Expat wrapper) and REXML (pure Ruby) parsers +# * possible to choose between REXML (pure Ruby) and LibXML/Nokogiri (compiled) parsers # * Marshalling Ruby objects to Hashes and reconstruct them later from a Hash # * SandStorm component architecture XMLRPC::Client interface # diff --git a/lib/xmlrpc/config.rb b/lib/xmlrpc/config.rb index bd13932..559f16a 100644 --- a/lib/xmlrpc/config.rb +++ b/lib/xmlrpc/config.rb @@ -15,6 +15,7 @@ module Config # # * XMLParser::REXMLStreamParser # * XMLParser::LibXMLStreamParser + # * XMLParser::NokogiriStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser # enable tag diff --git a/lib/xmlrpc/parser.rb b/lib/xmlrpc/parser.rb index 582046a..c6d398b 100644 --- a/lib/xmlrpc/parser.rb +++ b/lib/xmlrpc/parser.rb @@ -624,7 +624,51 @@ def parse(str) end end - Classes = [REXMLStreamParser, LibXMLStreamParser] + class NokogiriStreamParser < AbstractStreamParser + def initialize + require 'nokogiri' + @parser_class = NokogiriStreamListener + end + + class NokogiriStreamListener + include StreamParserMixin + + def self.handler + # We need to construct this on first use, since we cannot be sure Nokogiri is available + @handler ||= begin + Class.new(Nokogiri::XML::SAX::Document) do + def initialize(parent) + super() + @parent = parent + end + + def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = []) + @parent.startElement(name, attrs) + end + + def end_element_namespace(name, prefix = nil, uri = nil) + @parent.endElement(name) + end + + def characters(string) + @parent.character(string) + end + + def cdata_block(string) + @parent.character(string) + end + end + end + end + + def parse(str) + parser = Nokogiri::XML::SAX::Parser.new(self.class.handler.new(self)) + parser.parse(str) + end + end + end + + Classes = [REXMLStreamParser, LibXMLStreamParser, NokogiriStreamParser] # yields an instance of each installed parser def self.each_installed_parser