Groovy HTTPBuilder SOAP响应未正确解析

时间:2011-10-19 23:13:43

标签: soap groovy httpbuilder

我不明白为什么XmlSlurper显然没有处理结果。

import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*


def String WSDL_URL = ...
def http = new HTTPBuilder( WSDL_URL , ContentType.XML )
String soapEnvelope = 
          """<?xml version="1.0" encoding="utf-8"?>
        <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                         xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
          <soap12:Body>
            <GetTerritories xmlns="...">
              <State>AZ</State>
              <ZipCode>85203</ZipCode>
            </GetTerritories>
          </soap12:Body>
        </soap12:Envelope>"""
        http.request( POST, XML ) {
             headers."Content-Type" = "application/soap+xml; charset=utf-8"
             headers."Accept" = "application/soap+xml; charset=utf-8"
             body = soapEnvelope

            response.success = { resp, xml ->     
                println "XML was ${xml}"
                println "Territories were ${xml.Territories}"
                println "State were ${xml.Territories.State}"
                println "City was ${xml.Territories.Territory.City}"
                println "County was ${xml.Territories.Territory.County}"
            }

            response.failure = { resp, xml ->
                xml
            }
        } 

导致

XML was <Territories><State>AZ</State><ZipCode>85203</ZipCode><Territory><City>Mesa</City><County>Maricopa</County>...</Territory></Territories>
Territories were 
State were 
City was 
County was 

更新:感谢John Wagenleitner的洞察力,我做了一些挖掘。

当我添加断言时,我发现了一个问题:

assert "Territories" == xml.name()
                     |  |   |
                     |  |   Envelope
                     |  <Territories><State>AZ</State><ZipCode>85203</ZipCode</Territories>
                     false

将请求参数从POST, XML更改为POST, TEXT具有以下意义:

XML was <?xml version="1.0" encoding="utf-8"?>
<soap:Envelope 
      xmlns:soap="http://www.w3.org/2003/05/soap-envelope" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <soap:Body>
        <GetTerritoriesResponse xmlns="...">
            <GetTerritoriesResult>&lt;Territories&gt;&lt;State&gt;AZ&lt;/State&gt;&lt;ZipCode&gt;85203&lt;/ZipCode&gt;&lt;Territory&gt;&lt;City&gt;Mesa&lt;/City&gt;&lt;County&gt;Maricopa&lt;/County&gt;...&lt;/Territory&gt;&lt;/Territories&gt;
            </GetTerritoriesResult>
        </GetTerritoriesResponse>
    </soap:Body>
</soap:Envelope>

...

因此,当打印出变量时,看起来XmlSlurper正在抛弃SOAP内容并评估最内层节点(),而实际上并未导航到该节点。这是预期的行为吗?

我一直无法使用httpBuilder找到更完整和现代的SOAP调用和解析,因此我假设XML是正确的内容类型。但看起来我只需要接受TEXT并自己解析身体,这似乎很蹩脚。有没有更好的方法来处理使用httpBuilder的SOAP响应?

1 个答案:

答案 0 :(得分:1)

我建议打印回复的原始文本:

println "XML was ${resp.data.text}"

假设打印的XML行符合您的预期(虽然没有Envelope或Body节点,因此很奇怪),那么您应该能够从对xml的引用中删除 Territories 。使用XmlSlurper解析时,根节点是GPathResult。

assert "Territories" == xml.name()
println "State were ${xml.State.text()}"
println "City were ${xml.Territory.City.text()}"
println "County were ${xml.Territory.County.text()}"

另外,只是想指出SOAP 1.2媒体类型是“application / soap + xml”。

<强>更新

  

当打印变量时,它看起来像XmlSlurper   out,扔掉SOAP东西并评估最里面的节点   ()而实际上并没有导航到该节点。这是预期的   行为?

是的,GPathResult的toString()方法只打印所有文本节点,而不是实际的元素或属性。使用HTTPBuilder,您可以使用以下方法打印出原始响应文本:

println resp.data.text
  

我一直无法找到更完整和现代的SOAP调用   使用httpBuilder解析,所以我假设XML将是正确的内容   类型。但看起来我只需要接受TEXT并解析它   身体自己,这似乎很蹩脚。有没有更好的方法来处理SOAP   用httpBuilder做出回应?

ContentType.XML 很好,问题在于如何形成Web服务返回的SOAP响应。网络服务正在 GetTerritoriesResult 元素中将 Territories 结果作为编码字符串发回,而不是作为其中的一部分HTTPBuilder自动为您解析的实际XML响应(这不是HTTPBuilder处理它的方式的问题)。因为您真正想要的数据是在该编码字符串中,您需要自己解析 GetTerritoriesResult 的文本节点。

response.success = { resp, xml ->     
    println "XML was ${resp.data.text}"
    def territories = new XmlSlurper().parseText(
        xml.Body.GetTerritoriesResponse.GetTerritoriesResult.text()
    )
    println "State were ${territories.State}"
    println "City was ${territories.Territory.City}"
    println "County was ${territories.Territory.County}"
}