Search code examples
rubysoapsavon

Parsing Savon SOAP response with multiRef


I am attempting to access a SOAP service using the Ruby gem Savon. I can connect to the service and make a request and receive the response, but I cannot parse the response.

The response contains multiple href references to multiRef elements. When I try to decode it using

response.to_hash[:get_user_risk_profile_response][:get_user_risk_profile_return][:href]

I get #id0. How do I follow the id0 reference?

The SOAP response is below. Thanks!

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <getUserStatusResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <getUserStatusReturn href="#id0"/>
    </getUserStatusResponse>
    <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns1:UserRiskProfileBean" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://xrisk.api.example.com">
      <parameters xsi:type="ns2:ArrayOf_tns3_ParamBean" xsi:nil="true" xmlns:ns2="http://api.example.com"/>
      <siteID xsi:type="soapenc:string">UNKNOWN</siteID>
      <userID xsi:type="soapenc:string">sam.wiggins</userID>
      <userRiskScore href="#id1"/>
      <userRiskScoreDT xsi:type="xsd:dateTime">2011-02-16T18:15:50.012Z</userRiskScoreDT>
    </multiRef>
    <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">640</multiRef>
  </soapenv:Body>
</soapenv:Envelope>

Solution

  • It seems that the best approach, for the moment, was to just roll my own parsing using XPath. It's crude and probably not very bullet proof, but will do the job until something better comes along.

    class SavonResponseXMLParser
    
      def initialize(response_xml)
        @doc = REXML::Document.new(response_xml)
      end
    
      def get_property(property)
        property_value = nil
        elements = REXML::XPath.match(@doc, "//#{property}")
        if (elements.length == 1)
          element = elements[0]
          href = element.attributes['href']
          if (href)
            href =~ /^#id(\d+)/
            multiref_elements = REXML::XPath.match(@doc,"//multiRef[@id='id#{$1}']")
            if (multiref_elements.length == 1)
              multiref_element = multiref_elements[0]
              property_value = multiref_element.text 
            end
          else
            property_value = element.text
          end
        end
        return property_value
      end
    end