【问题标题】:Parsing Savon SOAP response with multiRef使用 multiRef 解析 Savon SOAP 响应
【发布时间】:2011-02-16 19:39:26
【问题描述】:

我正在尝试使用 Ruby gem Savon 访问 SOAP 服务。我可以连接到服务并发出请求并接收响应,但我无法解析响应。

响应包含对 multiRef 元素的多个 href 引用。当我尝试使用

对其进行解码时
response.to_hash[:get_user_risk_profile_response][:get_user_risk_profile_return][:href]

我得到#id0。如何遵循 id0 参考?

SOAP 响应如下。谢谢!

<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>

【问题讨论】:

    标签: ruby soap savon


    【解决方案1】:

    目前看来,最好的方法是使用 XPath 滚动我自己的解析。它很粗糙,可能不是很防弹,但会在出现更好的情况之前完成这项工作。

    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
    

    【讨论】:

      【解决方案2】:

      您必须手动解析引用:

      id = response.to_hash[:get_user_risk_profile_response][:get_user_risk_profile_return][:href]
      references = response.to_hash[:multi_ref]
      result = references.select {|ref| ref[:id] == id.sub('#', '') }
      

      我建议将上述内容放在辅助方法/模块中:

      module MultiRef
        def resolve_ref(id)
          references = to_hash[:multi_ref]
          references.select {|ref| ref[:id] == id.sub('#', '') }
        end
      end
      Savon::Response.send(:include, MultiRef)
      

      然后简单地做:

      response.resolve_ref("#id1")
      

      href 哈希值递归替换为其适当的引用值留给读者作为练习;)

      【讨论】:

      • 我尝试了类似的方法,但遇到了障碍。我的一个 SOAP 响应包含最大 #id10 的参考值。 response.to_hash 方法将 10 个 multiRef 元素解码为一个数组。不幸的是,数组中值的顺序不一定是连续的。例如,multiRef href=#id5" 最终不会成为数组中的第 5 项。它可以是数组中的任何项。我认为这是 to_hash 方法中的错误。
      • 另外,我相信 Savon 开发人员目前正在努力正确处理多部分响应。同时,我通过使用 REXML::XPath 来查询 response.to_xml 字符串来解析响应。这工作正常。
      • 上述解决方案应该可以工作,因为它通过实际 ID 查找,而不是通过数组索引。但是,是的,在原始 XML 响应上使用 XPath 更有意义。
      • 哦,顺便说一句,为什么不在这里发布您的解决方案?回答的问题比部分解决方案更有价值,即使您是在回答自己的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-26
      • 1970-01-01
      • 1970-01-01
      • 2020-04-22
      相关资源
      最近更新 更多