Compartilhar via


Ler um envelope SOAP em Transact-SQL

Introdução

Este artigo tem sua origem em uma pergunta postada no Fórum TechNet Brasil do SQL Server - Ler envelope do SOAP e irá fornecer à você um problema sobre o consumo de um pacote XML estruturado através do protocolo SOAP, recebido através de um Web Service para consultar seus dados em T-SQL.

Esta é uma das possíveis soluções relacionadas para este problema, se você conhece outras opções em T-SQL que atendam à necessidade do problema proposto, fique à vontade para acrescentar seu conteúdo neste artigo.

Problema

Durante minha leitura nos Threads do Fórum de SQL, encontrei à seguinte pergunta.

A pergunta era: "Estou consumindo um Web Service via T-SQL e preciso ler o envelope de retorno dele. O retorno esta assim:"

 

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <IntegraPJResponse>
      <IntegraPJResult xsi:type="xsd:string">
        <retorno sucesso="true">
          <id>7d8444e6-4d78-e311-895e-00155d0b0b36</id>
        </retorno>
      </IntegraPJResult>
    </IntegraPJResponse>
  </soap:Body>
</soap:Envelope>

O XML indicado pelo inquiridor é um Envelope de retorno válido obtido através de um Web Service. Esta validação pode ser executada através de qualquer ferramenta de XML Parser. Neste caso, estou utilizando o Microsoft XML Parser (KB 324460).

Neste caso, o foco do problema está isolado no consumo do envelope do SOAP, já que o recebimento através do Web Service foi realizado com sucesso. Mesmo não sendo claro, o inquiridor quer obter exatamente a chave GUID indicada dentro do nó retorno. Exatamente o valor do nó id.

Causas

Quando recebemos um XML de um Web Service ele pode ter apenas dois tipos de retorno: com sucesso (onde o XML possui um formato definido) ou com falha onde o XML retorna apenas o cabeçalho do Web Service e uma mensagem de erro que pode ser retornada por um método do Web Service ou por problema na estrutura do XML. Neste caso, o consumidor destes dados deve estar preparado para receber o XML em ambos os casos.

O problema deste Thread no Fórum era mais simples, apesar de que o inquiridor não tinha certeza se estava recebendo a resposta do seu Web Service corretamente.

A validação é simples, já que basta o XML ser válido e possuir os devidos namespaces para identificação do objeto e seus devidos nós.

Solução

Precisamos identificar quais são os nós que correspondem à resposta do Web Service e seu efetivo resultado.

No caso do XML encaminhado pelo inquiridor, é simples já que todo conteúdo está dentro do nó Body, e este nó possui apenas um nó filho Response o que é comum neste tipo de retorno. Já no caso do nó Result o SOAP pode ter mais de um nó (o que n��o é muito comum), mas não é este o caso já que possui apenas uma resposta.

Dentro do nó Result está o conteúdo que realmente interessa ao inquiridor. O XML criado efetivamente para retornar pelo Web Service e ser consumido pelo banco de dados.

Então, temos à seguinte ordem:

  • nó Response:  IntegraPJResponse
  • nó Result: IntegraPJResponse
  • nó de Retorno (conteúdo esperado): retorno\id

Para manipular corretamente o XML em T-SQL, "setamos" o conteúdo do XML em uma variável do tipo xml, que chamamos de @x. Após isto, consultamos o XML através da variável @x, como se estivéssemos realizando uma consulta em uma tabela de um banco de dados do SQL Server.

Os critérios que fazem toda diferença para tornar esta solução em uma consulta simples e prática é identificar exatamente o namespace recebido no XML do Web Service e mapear os nós até o valor ou atributo desejado.

Neste caso, declaramos o namespace soap (padrão deste tipo de solução), indicando à sua referência de validação, neste caso o endereço Web http://schemas.xmlsoap.org/soap/envelope/.

O mapeamento do XML pode ser um pouco trabalhoso, dependendo da quantidade de nós indicada no XML e o que realmente precisamos consumir.

Para o inquiridor, o número GUID é o suficiente, então fica mais fácil. Mapeamos os nós na consulta até o pai do nó id (onde está o valor que desejamos) que é o nó retorno e fazemos à referência para localizar à informação em T-SQL. Os objetos para executar esta tarefas são nomeados pelo desenvolvedor e referenciam o conteúdo da propriedades do XML, neste caso, chamei de RETORNO a declaração do namespace para que o Parser XML do SQL Server possa identificar os nós Envelope e Body, e  chamei de VALOR o caminho até o nó retorno, para obter o nó id.

Na instrução SELECT é necessário informar qual propriedade do nó desejamos. Como precisamos do valor, declaramos à funcão value e seu conteúdo deve ser o nó id e sua conversão para um tipo de dado válido no SQL Server. Para demostração, definir como varchar.

Vamos executar à isntrução para verificar o resultado. Segue abaixo o script T-SQL desta solução:


DECLARE @x xml

SET @x='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <IntegraPJResponse>
      <IntegraPJResult xsi:type="xsd:string">
        <retorno sucesso="true">
          <id>7d8444e6-4d78-e311-895e-00155d0b0b36</id>
        </retorno>
      </IntegraPJResult>
    </IntegraPJResponse>
  </soap:Body>
</soap:Envelope>'

 

SELECT RETORNO.VALOR.value('id[1]','varchar(100)') AS VALOR_ID
FROM @x.nodes(

'declare namespace soap="http://schemas.xmlsoap.org/soap/envelope/";
/soap:Envelope/soap:Body/IntegraPJResponse/IntegraPJResult/retorno') as RETORNO(VALOR)

GO

O resultado é exibido após a execução desta instrução no SSMS. Veja o resultado na imagem abaixo:


Veja Também

Leia alguns tópicos relacionados ao assunto: