Bom, o XML é um padrão de arquivo multihierarquico o qual sua estrutura não tem um fim definido, pois podemos ter muitos nós aninhados dentro dos outros, mas para não confundir sempre usamos no maximo 2 ou 3.
No XML a seguir capturado via web-service em 5Win/Harbour voce podem ver uma pequena estrutura:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<calculo_precos>
<versao_arquivo>1.0</versao_arquivo>
<dados_postais>
<servico>40010</servico>
<servico_nome>SEDEX</servico_nome>
<uf_origem></uf_origem>
<local_origem></local_origem>
<cep_origem>05171340</cep_origem>
<uf_destino></uf_destino>
<local_destino></local_destino>
<cep_destino>88330000</cep_destino>
<peso>31</peso>
<mao_propria>0</mao_propria>
<aviso_recebimento>0</aviso_recebimento>
<valor_declarado>0</valor_declarado>
<tarifa_valor_declarado>0</tarifa_valor_declarado>
<preco_postal>0</preco_postal>
</dados_postais>
<erro>
<codigo>-4</codigo>
<descricao>Peso excedido</descricao>
</erro>
</calculo_precos>
</xml>
Portanto o trabalho com nós do mesmo não é assim tão fácil de se manipular
Com o exemplo acima minha função XMLGet() cai como uma luva para obter dados do arquivo.
No codigo que segue apresento o .RC da DIALOGo principal de interface com o usuário:
Salve como SEDEX.RC
Sedex DIALOG 28, 62, 267, 175
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "DIALOG_1"
FONT 8, "MS Sans Serif"
{
EDITTEXT 101, 37, 17, 47, 12
EDITTEXT 102, 168, 17, 47, 12
EDITTEXT 103, 78, 50, 67, 12
PUSHBUTTON "Calcular Envio", 105, 149, 50, 107, 27
EDITTEXT 104, 78, 65, 67, 12
LTEXT "Nenhuma operação em curso.", 106, 10, 97, 247, 67
GROUPBOX "Origem", -1, 4, 5, 128, 32, BS_GROUPBOX
GROUPBOX "Calculo", -1, 4, 38, 259, 46, BS_GROUPBOX
GROUPBOX "Mensagem", -1, 4, 87, 259, 82, BS_GROUPBOX
LTEXT "CEP:", -1, 9, 18, 26, 8
LTEXT "Peso em Gramas:", -1, 10, 52, 60, 8
LTEXT "Total a Pagar R$:", -1, 11, 66, 60, 8
GROUPBOX "Destino", -1, 135, 5, 128, 32, BS_GROUPBOX
LTEXT "CEP:", -1, 140, 18, 26, 8
}
O codigo a seguir é um web-service que tem por função passar parâmetros ao servidor de serviços dos Correios afim de trazer uma resposta dada por seus serviços on-line.
Imagine que o mesmo método poderá ser usado para enviar dados ao Seraza e SPC e trazer o resultado da pesquisa validando ou não o crédito de um cliente.
O código a seguir, feito em 5Win 2.7 e Harbour 45 pode ser adaptado a qualquer versão ou até a qualquer GUI que não 5Win e demonstra de forma clara com é feito este trabalho.
Salve como SEDEX.PRG
#include "fivewin.ch"
static xDLL,oGet,oSay
Function Main()
local oDlg, oFont
local cCEP1:=space(9), cCEP2:=space(9), cPESO:=0 , cTOTAL := 0
DEFINE FONT oFont NAME "ARIAL" SIZE 00,-12 BOLD
SET _3DLOOK ON
DEFINE DIALOG oDlg RESOURCE "Sedex" TITLE "Correios - Sedex"
REDEFINE GET oGet101 VAR cCEP1 PICTURE "99999-999" ID 101 OF oDlg
REDEFINE GET oGet102 VAR cCEP2 PICTURE "99999-999" ID 102 OF oDlg
REDEFINE GET oGet103 VAR cPESO PICTURE "999999999" ID 103 OF oDlg
REDEFINE GET oGet104 VAR cTOTAL PICTURE "@E 99,999.99" ID 104 OF oDlg
REDEFINE BUTTON ID 105 OF oDlg ACTION Consulta(cCEP1,cCEP2,cPESO,oGet104,oSay106)
REDEFINE SAY oSay106 MEMO ID 106 OF oDlg COLOR nRGB(255,0,0),getsyscolor(15)
ACTIVATE DIALOG oDlg CENTERED
return nil
Function Consulta(cCepOrigem,cCepDestino,cPeso,oTotal,oSay)
local oRs, ws
ws := TdWebService():new()
oSay:SetText( "Aguarde. consulta base de dados" )
cXMLSedex := ws:OpenWS( "http://www.correios.com.br/encomendas/precos/calculo.cfm?" +;
"&cepOrigem="+cCepOrigem+;
"&cepDestino="+cCepDestino+;
"&peso="+alltrim(str(cPeso))+;
"&resposta=xml" )
ws:end()
oSay:SetText( "Aguarde. salvando o resultado" )
MemoWrit( "sedex.xml", cXMLSedex )
cXMLPreco := XMLGet( "preco_postal", cXMLSedex )
cXMLErros := XMLGet( "descricao" , cXMLSedex )
cTotal := transf( val( cXMLPreco ), "@E 99,999.99" )
oGet104:Refresh()
oGet104:SetText( cTotal )
oSay:SetText( iif( empty( cXMLErros ), "Operacao bem sucedida", cXMLErros ) )
return nil
Function XMLGet( XMLField, XMLFile )
XMLField := alltrim( XMLField )
XMLFieldINI := rat( "<"+XMLField+">", XMLFile ) + len( "<"+XMLField+">" )
XMLFieldEND := rat( "</"+XMLField+">", XMLFile ) - XMLFieldINI
return substr( XMLFile, XMLFieldINI, XMLFieldEND )
#include "Websrvce.prg"
Abaixo vemos a classe WebService que é a responsável por fazer a ponte entre nosso aplicativo e o ponto distante do mesmo.
Salve como WEBSRVCE.PRG
/*
*
* Classe WebService
*
*/
#include "dll.ch"
//static xdll
CLASS TdWebService
DATA hOpen
DATA sbuffer HIDDEN
DATA xDLL HIDDEN
METHOD New(buffersize) CONSTRUCTOR
METHOD OpenWS(url)
METHOD End()
ENDCLASS
*****************************
METHOD New(conexion,buffersize) CLASS TdWebService
DEFAULT buffersize:=3200
::sbuffer:=buffersize
xDll:=LoadLib32("wininet.dll")
::hOpen = InternetOpen("TdWebService", 1,,, 0)
RETURN Self
*****************************
METHOD OpenWS(url) CLASS TdWebService
local hFile,ret,xml
hFile = InternetOpenUrl(::hOpen, url,"",0,,0)
xml:=space(::sbuffer)
InternetReadFile(hFile, @xml, ::sbuffer, @Ret)
return subst(alltrim(xml),1,len(alltrim(xml))-5)
*****************************
METHOD End() CLASS TdWebService
FreeLib32(xDll)
return nil
*****************************
DLL32 FUNCTION InternetOpen( cApp as LPSTR, n1 AS DWORD, n2 AS LPSTR, n3 AS LPSTR,;
n4 AS DWORD ) AS LONG PASCAL ;
FROM "InternetOpenA" LIB xdll
Dll32 Function InternetReadFile(hFile As 7, @sBuffer As 8, lNumBytesToRead As 7, @lNumberOfBytesRead As 7) As 7 PASCAL Lib xdll
Dll32 Function InternetOpenUrl(hInternetSession As 7, lpszUrl As 8, lpszHeaders As 8, dwHeadersLength As 7, dwFlags As 7, dwContext As 7) As 7 FROM "InternetOpenUrlA" PASCAL Lib xdll
DLL32 FUNCTION InternetCloseHandle( hSession AS LONG ) AS BOOL PASCAL LIB xdll
Tenho feito outros web-services para meu aplicativo e sei que mesmo ainda usando o xBase vejo que não existem mais segredos e nem barreiras que eu não consiga transpor, além do próprio Céu.
"E que Deus seja louvado!"