SOAP4R with Hpricot

SOAP4R is the Ruby SOAP toolkit making it easy to prop up a web service or set up a client to access a remote API. Hpricot is an amazing HTML/XML parser. It has a C back-end and is extremely fast (I would say it’s faster then libxml wrapper in my opinion). But what happens when you want to send an XML document over SOAP without SOAP4R mucking it all up (in most cases SOAP4R will just choke and leave you with some obscure “Can’t translate crocodiles into SOAP::Object” message. Alas, in version 1.5.8 SOAP4R has the ability to simply wrap the XML and send it on its way.

Cool huh? Oh wait, you can only use REXML Documents/Elements for this, and as we all know REXML is not really a speed demon. Besides if the rest of your code uses Hpricot why switch to REXML and back again just for SOAP stuff. Well, the key in the paragraph describing the XML pass-through feature is “… or any class with ‘to_xmlpart’ method”. Hpricot::Doc doesn’t have ‘to_xmlpart’ method, but you wouldn’t really need out. Behold the following:

xml_container.rb:


class XMLContainer
   def initialize(xml)
      @xml = xml
   end
   def to_xmlpart
     @xml
   end
end

XMLContainer class has ‘to_xml’ method and thus can be passed directly into SOAP4R calls without the fear of blow-up:



require 'xml_container'
require 'hpricot'

require 'soap/rpc/driver'

# Do SOAP initialization here and get the RPC driver ready to make SOAP calls
# ...

xml_doc = Hpricot::XML(File.read("MyXML.xml"))
xml_can = XMLContainer.new xml_doc.to_html

soapdriver->add_method("SendStuff","myXml")

soapdriver->SendStuff xml_can

And there you go. Have fun kids :)

Correction: in the newest version of SOAP4R they changed the method from to_xml to to_xmlpart. I’ve update the code above to reflect that change.

5 Responses to “SOAP4R with Hpricot”

  1. Scott Rippee Says:

    You can just add the method to the class

    require ‘hpricot’

    class Hpricot
    def to_xmlpart
    self.to_html
    end
    end

    create your hpricot object here.

    Or

    make your converter class inherits from Hpricot and extends its functionality.

    class MyClass add_method(”SendStuff”,”myXml”)
    soapdriver->SendStuff xml_doc

  2. Scott Rippee Says:

    Eww it jacked up my comment.. Lets try this again.

    Or

    make your converter class inherits from Hpricot and extends its functionality.

    class MyClass < Hpricot
    def to_xmlpart
    to_html
    end
    end

    xml_doc=MyClass::XML(File.read(”MyXML.xml”))
    soapdriver->add_method(”SendStuff”,”myXml”)
    soapdriver->SendStuff xml_doc

  3. mzolin Says:

    Hpricot is a module, so it’s a little more tricky than that, but the idea is right. The upside to just having any string in the class is you can do things like:

    xml = XMLContainer.new “#{@stuff}”

    and then send it, which would essentially cut your processing time to 0ms.

  4. Scott Rippee Says:

    You could then make a new module that extends the Hpricot module and implement to_xmlpart in your new module.

    I’m not sure if you can inject a new method into a module, but I think that can be done as well.

  5. SOAP in Ruby with Hpricot (a better way) « My Dog Knows C++ Says:

    [...] 26th, 2007 Ok, after a bit a comment war on the previous port (SOAP4R with Hpricot) I feel the need to present a better way of dealing with XML pass-through using Hpricot. This is [...]

Leave a Reply