Ответ Groovy HTTPBuilder SOAP не анализируется должным образом

Я не понимаю, почему 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 будет правильным типом контента. Но похоже, что мне просто придется принять ТЕКСТ и самому разобрать тело, что кажется хромым. Есть ли лучший способ обработки ответов SOAP с помощью httpBuilder?


person Visionary Software Solutions    schedule 19.10.2011    source источник


Ответы (1)


Я бы рекомендовал распечатать необработанный текст ответа:

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, когда переменная выводится, отбрасывает материал SOAP и оценивает самый внутренний узел (), фактически не переходя к этому узлу. Это ожидаемое поведение?

Да, метод toString() для GPathResult просто печатает все текстовые узлы, а не фактические элементы или атрибуты. С помощью HTTPBuilder вы можете распечатать необработанный текст ответа, используя:

println resp.data.text

Мне не удалось найти более полный и современный вызов SOAP и выполнить синтаксический анализ с помощью httpBuilder, поэтому я предположил, что XML будет правильным типом контента. Но похоже, что мне просто придется принять ТЕКСТ и самому разобрать тело, что кажется хромым. Есть ли лучший способ обработки ответов SOAP с помощью httpBuilder?

С ContentType.XML все в порядке, проблема заключается в том, как формируется ответ SOAP, возвращаемый вашей веб-службой. Веб-служба отправляет обратно результаты Territories в виде закодированной строки в элементе GetTerritoriesResult, а не как часть фактический XML-ответ, который HTTPBuilder автоматически анализирует для вас (это не проблема с тем, как 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}"
}
person John Wagenleitner    schedule 20.10.2011
comment
Спасибо, этот комментарий был очень полезным. Из того, что я читал о рецептах Groovy Скотта Дэвиса, я подумал, что text() предназначен для XmlParser, а не для XmlSlurper. Однако я заблокирован несоответствием между распечаткой ${xml} и ${xml.name()}. Вы знаете, почему это происходит? - person Visionary Software Solutions; 20.10.2011
comment
При печати xml GPathResult он не показывает теги, а только текстовое содержимое, поэтому вы видите результат, который вы видели. - person John Wagenleitner; 22.10.2011
comment
Если вы вызовете text() для GPathResult, он вернет строку с текстовым содержимым этого элемента. При выполнении таких действий, как println, обычно это не является строго необходимым, поскольку метод toString() в GPathResult также распечатывает текстовое содержимое элемента. - person John Wagenleitner; 22.10.2011