【问题标题】:Groovy HTTPBuilder SOAP response not being parsed properlyGroovy HTTPBuilder SOAP 响应未正确解析
【发布时间】:2011-10-19 23:13:42
【问题描述】:

我不明白为什么 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 内容并评估最里面的节点 () 而实际上并未导航到该节点。这是预期的行为吗?

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

【问题讨论】:

    标签: soap groovy httpbuilder


    【解决方案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 响应是如何形成的。 Web 服务将 Territories 结果作为 GetTerritoriesResult 元素中的编码字符串发送回,而不是作为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}"
    }
    

    【讨论】:

    • 谢谢,这条评论很有帮助。根据我对 Scott Davis 的 Groovy Recipes 的阅读,我认为 text() 用于 XmlParser,而不是 XmlSlurper。不过,我被 ${xml} 和 ${xml.name()} 的打印输出不匹配所困扰。你知道它为什么这样做吗?
    • 当打印出 xml GPathResult 时,它不显示标签,只显示文本内容,所以这就是你看到你看到的结果的原因。
    • 如果您在 GPathResult 上调用 text(),它将返回一个包含该元素文本内容的字符串。在执行 println 之类的操作时,通常不是绝对必要的,因为 GPathResult 上的 toString() 方法也会打印出元素的文本内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    相关资源
    最近更新 更多