Na
postagem anterior aprendemos como usar a classe THTTPSend da
biblioteca synapse para criar consultar o
serviço de consulta de cep e receber um xml com as informações sobre o endereço.
Hoje vamos ver como criar uma classe para encapsular todo esse mecanismo e fazer com que os atributos dessa classe sejam os dados do endereço.
Primeiro de tudo vamos criar um arquivo chamado LazCep.pas e a classe LazCep. Repare nas units que temos que adicionar no uses.
uses
Classes, SysUtils, DOM, XMLRead, httpsend, dialogs;
type
{ TLazCep }
TLazCep = class
private
FXML: DOMString;
FCEP: DOMString;
FXMLDoc: TXMLDocument;
//sets
procedure SetCep(const vCep: DOMString);
//gets
function GetCep: DOMString;
function GetLogradouro: DOMString;
function GetCidade: DOMString;
function GetEstado: DOMString;
function GetBairro: DOMString;
function GetIBGEEstado: DOMString;
function GetIBGECidade: DOMString;
function GetIBGEVerificador: DOMString;
//internal functions
function GetXmlNode(const vNodeName: DOMString): DOMString;
public
constructor Create;
destructor Destroy;
procedure Consultar;
function GetXML: DOMString;
property Cep: DOMString read GetCep write SetCep;
property Logradouro: DOMString read GetLogradouro;
property Cidade: DOMString read GetCidade;
property Estado: DOMString read GetEstado;
property Bairro: DOMString read GetBairro;
property IBGEEstado:DOMString read GetIBGEEstado;
property IBGECidade:DOMString read GetIBGECidade;
property IBGEVerificador: DOMString read GetIBGEVerificador;
end;
Feito isso pressione shift+ctrl+c para criar o esqueleto da classe. Implemente a classe de modo que a propriedade CEP seja um simples Get e Set, mas dê atenção especial aos métodos consultar e GetXmlNode.
{ TLazCep }
procedure TLazCep.SetCep(const vCep: DOMString);
begin
FCEP:=vCep;
end;
function TLazCep.GetCep: DOMString;
begin
Result := FCEP;
end;
function TLazCep.GetLogradouro: DOMString;
begin
Result := GetXmlNode('logradouro');
end;
function TLazCep.GetCidade: DOMString;
begin
Result := GetXmlNode('cidade');
end;
function TLazCep.GetEstado: DOMString;
begin
Result := GetXmlNode('uf');
end;
function TLazCep.GetBairro: DOMString;
begin
Result := GetXmlNode('bairro');
end;
function TLazCep.GetIBGEEstado: DOMString;
begin
Result := GetXmlNode('ibge_uf');
end;
function TLazCep.GetIBGECidade: DOMString;
begin
Result := GetXmlNode('ibge_municipio');
end;
function TLazCep.GetIBGEVerificador: DOMString;
begin
Result := GetXmlNode('ibge_municipio_verificador');
end;
function TLazCep.GetXmlNode(const vNodeName: DOMString): DOMString;
begin
Result := FXMLDoc.FindNode('webservicecep').FindNode('retorno').FindNode(vNodeName).TextContent;
end;
constructor TLazCep.Create;
begin
//constructor
end;
destructor TLazCep.Destroy;
begin
//destructor
end;
procedure TLazCep.Consultar;
var
host: string;
{streams que conterão o resultado do site}
Response: TMemoryStream;
S: TStringStream;
begin
host := 'http://www.buscarcep.com.br/?' + 'cep='+FCEP+'&formato=xml&chave='+UrlEncode('1Z3s3/2ZjDt.dcyiLuBy/6mitlDNgt/');
{destruindo o XMLDoc caso já exista}
if(FXMLDoc <> nil) then
try
FXMLDoc.Free;
except
end;
FXMLDoc := nil;
try
{criando os streams que conterão o resultado do site}
Response:=TMemoryStream.Create;
{consultando com httpGetText ou httpGetBinary}
if HttpGetBinary(host, Response) then
begin
{posiciona o stream de resposta no inicio}
Response.Seek(0, soFromBeginning);
{Cria e Lê o documento XML a partir da stream}
ReadXMLFile(FXMLDoc, Response);
{posiciona o stream de resposta no inicio novamente}
Response.Seek(0, soFromBeginning);
{Copia o stream de resposta para um string stream, recém criado, para extrair dele uma string}
S := TStringStream.Create(FXML);
S.CopyFrom(Response, Response.Size-1);
s.Seek(0, soFromBeginning);
{atribui o conteudo todo a propriedade XML da classe, para termos acesso ao xml de retorno}
FXML:= s.DataString;
{coloco o encoding desejado}
FXMLDoc.Encoding:='iso-8859-1';
end;
finally
Response.Free;
S.Free;
end;
end;
function TLazCep.GetXML: DOMString;
begin
Result := FXML;
end;
end.
Na seção implementation dessa unit colocamos o método estático que criamos na primeira parte desse tutorial, para encoding de URL.
O ponto principal aqui é o método Consultar. Repare que criamos um FXMLDoc: TXMLDocument como campo privado da classe TLazCep, certo? Esse atributo será destruido e recriado toda vez que se consultar um CEP, para limpar a estrutura XML que ele já tinha.
Logo depois criamos um memory stream, mas pode ser um string stream ou mesmo um stringList, dependendo de como você quer fazer
Posicionamos esse stream no início (não precisa fazer isso se for uma string), criamos e alimentamos o XMLDocument e ainda extraimos o conteudo do XML para um atributo da classe, para consulta ou conferência.
Depois disso a function GetXmlNode traz o conteudo do nó correto do XML, que tem o nome do dado que queremos.
Result := FXMLDoc.FindNode('webservicecep').FindNode('retorno').FindNode(vNodeName).TextContent;
Logo depois disso podemos usar GetXmlNode para cada um dos gets das propriedades da classe. Todas são somente leitura, exceto a CEP, e todas tem um get como este:
function TLazCep.GetLogradouro: DOMString;
begin
Result := GetXmlNode('logradouro');
end;
Exceto a CEP, já que é por ela que começamos.
Como vimos, obrigatoriamente um TXMLDoc deve ser criado pelo método estático global AKA procedure ReadXMLFile, que cria o objeto XMLDoc e popula seu conteudo através de uma stream. Enquanto o XMLDoc está na unit DOM, a procedure ReadXmlFile está na unit XMLRead.
Repare também que não fizemos o request HTTP com o HTTPSend "na unha", mas usamos a procedure HTTPGetBinary da unit HTTPSend que faz exatamente o que fizemos no último tutorial:
function HttpGetBinary(const URL: string; const Response: TStream): Boolean;
var
HTTP: THTTPSend;
begin
HTTP := THTTPSend.Create;
try
Result := HTTP.HTTPMethod('GET', URL);
if Result then
begin
Response.Seek(0, soFromBeginning);
Response.CopyFrom(HTTP.Document, 0);
end;
finally
HTTP.Free;
end;
end;
Até agora usamos o método HTTPGetBinary em conjunto com MemoryStreams. Podemos usar HTTPGetText em conjunto com StringLists, conforme segue:
procedure TLazCep.ConsultarString;
var
host: string;
{StringList que conterão o resultado do site}
Response: TStringList;
S: TStringStream;
begin
host := 'http://www.buscarcep.com.br/?' + 'cep='+FCEP+'&formato=xml&chave='+UrlEncode('1Z3s3/2ZjDt.dcyiLuBy/6mitlDNgt/');
{destruindo o XMLDoc caso já exista}
if(FXMLDoc <> nil) then
try
FXMLDoc.Free;
except
end;
FXMLDoc := nil;
try
{criando o stringlist que conterão o resultado do site}
Response:=TStringList.Create;
{consultando com httpGetText ou httpGetBinary}
if HttpGetText(host, Response) then
begin
{capturamos em uma string o conteudo do response}
FXML:=Response.Text;
{criamos uma string stream a partir dele para alimentar o XMLDoc}
S := TStringStream.Create(FXML);
{Criamos e alimentamos o XMLDoc}
ReadXMLFile(FXMLDoc, S);
{coloco o encoding desejado}
FXMLDoc.Encoding:='iso-8859-1';
end;
finally
Response.Free;
S.Free;
end;
end;
Essa classe ainda não funciona com proxy. Para funcionar com proxy precisaremos usar recursos especiais que serão vistos nos próximos tutoriais.
Outra coisa que precisamos é validar e disparar a mensagem de erro correta caso o xml venha vazio ou caso não seja possível estabelecer uma conexão.
Nos próximos artigos veremos como usar esta classe e como fazer essas alterações necessárias.
Ainda precisamos cuidar de conversões e codificações UTF-8 etc por causa de acentos e outros sinais diacríticos.
No próximo artigo faremos mais melhorias nesta classe. E no final poderemos fazer download do código fonte completo. Até lá :)
Ir Para:
Parte 1 |
Parte 2 |
Parte 3 |
Parte 4 |
Parte 5
Comentários
Postar um comentário