Groovy HTTPBuilder SOAP 响应未正确解析

发布于 2024-12-11 07:25:27 字数 3313 浏览 0 评论 0原文

我不明白为什么 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 

更新:感谢约翰瓦根莱特纳的洞察力,我做了更多的挖掘。

当我添加该断言时,我看到一个问题:

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 响应?

I don't understand why XmlSlurper is apparently not working on the result.

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

leads to

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 

UPDATE: Thanks to John Wagenleitner's insight, I did a little more digging.

When I add that assert, I see an issue:

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

Changing the request parameters from POST, XML to POST, TEXT is revealing:

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><Territories><State>AZ</State><ZipCode>85203</ZipCode><Territory><City>Mesa</City><County>Maricopa</County>...</Territory></Territories>
            </GetTerritoriesResult>
        </GetTerritoriesResponse>
    </soap:Body>
</soap:Envelope>

...

So it looks like the XmlSlurper, when the variable is being printed out, is throwing away the SOAP stuff and evaluating the innermost node () while not actually navigating to that node. Is this expected behavior?

I have been unable to find a a more complete and modern SOAP call and parse using httpBuilder, so I assumed XML would be the right content type. But it looks like I'll just have to accept TEXT and parse the body myself, which seems lame. Is there a better way of handling SOAP responses with httpBuilder?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

娇纵 2024-12-18 07:25:27

我建议打印响应的原始文本:

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

假设打印的 XML 行是您所期望的(尽管很奇怪,因为没有 Envelope 或 Body 节点),那么您应该能够从中删除 Territories您对 xml 的引用。当使用 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}"
}

I would recommend printing the raw text of the response:

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

Assuming that the printed XML line is what you expect (though odd since there is no Envelope or Body nodes), then you should be able to remove Territories from your references to xml. When parsed with XmlSlurper the root node is the 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()}"

Also, just wanted to point out that the SOAP 1.2 media type is "application/soap+xml".

UPDATE:

So it looks like the XmlSlurper, when the variable is being printed
out, is throwing away the SOAP stuff and evaluating the innermost node
() while not actually navigating to that node. Is this expected
behavior?

Yes, the toString() method for a GPathResult just prints all text nodes and not the actual elements or attributes. With HTTPBuilder you can print out the raw response text by using:

println resp.data.text

I have been unable to find a a more complete and modern SOAP call and
parse using httpBuilder, so I assumed XML would be the right content
type. But it looks like I'll just have to accept TEXT and parse the
body myself, which seems lame. Is there a better way of handling SOAP
responses with httpBuilder?

The ContentType.XML is fine, the issue is with how the SOAP response that your web service returns is formed. The web service is sending back the Territories results as an encoded string in the GetTerritoriesResult element and not as part of the actual XML response that HTTPBuilder automatically parses for you (this is not a problem with the way HTTPBuilder is handling it). Because the data you really want is in that encoded string you will need to parse the text node of the GetTerritoriesResult yourself.

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}"
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文