1 - O objeto XMLHttpRequest
e o XML DOM
O XMLHttpRequest é um objeto ou um conjunto
de instruções de código JavaScript que
permite efetuar uma conexão com um servidor usando o
protocolo HTTP. Este objeto é o responsável pela
parte mais importante do processamento assíncrono usando
AJAX, pois é suportado por todos os navegadores de maior
importância, tais como Mozilla Firefox, Internet Explorer
5+, Safari e Opera 7+.
O objeto XMLHttpRequest trabalha nos bastidores
das páginas web, ou seja, à medida que o usuário
interage com a aplicação, é possível
efetuar requisições a um servidor web e obter
dados que possibilitarão atualizar ou validar os dados
informados pelo usuário de forma assíncrona
com suas atividades.
Em resumo, o funcionamento do objeto XMLHttpRequest
pode ser exemplificado na figura seguinte:
O fluxo de dados na figura acima deixa claro o envolvimento
das várias tecnologias abordadas neste trabalho. Tem-se
uma página HTML cujos elementos podem ser acessados
e manipulados usando JavaScript (via HTML DOM). O objeto XMLHttpRequest
efetua requisições ao servidor web (fornecendo
alguns parâmetros) e obtém respostas em formato
XML. Uma linguagem dinâmica (JSP, PHP, Perl, etc) é
responsável por efetuar a conexão com o servidor
de dados e retornar as informações solicitadas.
Esta mesma linguagem dinâmica é a responsável
por construir o documento XML e enviá-lo ao objeto
XMLHttpRequest.
1.1 - Como instanciar o objeto XMLHttpRequest e verificar
a compatibilidade entre navegadores
Antes de usar o objeto XMLHttpRequest para efetuar requisições
a um servidor web, é preciso construí-lo usando
códigos JavaScript. Esta tarefa nem sempre é
fácil devido à incompatibilidade entre os navegadores
em relação a este objeto.
Nos navegadores Firefox, Netscape, Safari e Opera, este objeto
possui o nome de XMLHttpRequest, enquanto o Internet Explorer
o implementa como um objeto ActiveX com os nomes de Microsoft.XMLHTTP
ou Msxml2.XMLHTTP (dependendo das bibliotecas disponíveis
no navegador). Assim, o primeiro passo na criação
do objeto de requisição (XMLHttpRequest), é
efetuar o teste de suporte no navegador. O trecho de código
a seguir mostra como isso pode ser feito:
<script language="javascript">
<!--
var http; // referência ao objeto XMLHttpRequest
if(window.XMLHttpRequest){
http = new XMLHttpRequest();
}
else if(window.ActiveXObject){
http = new ActiveXObject("Microsoft.XMLHTTP");
}
else{
http = null;
}
if(http){
// objeto XMLHttpRequest instanciado...pode
usar
alert("Objeto XMLHttpRequest
instanciado com sucesso.");
}
//-->
</script>
Antes de usar o objeto, porém, é importante
verificar se este foi criado com sucesso. A abordagem mais
comum é verificar se a variável que representa
o objeto é diferente de null. Em JavaScript
isso pode ser feito da seguinte forma:
if(http){
// objeto criado com sucesso!
}
Este trecho de código define uma variável global
que receberá o objeto de requisição.
Em aplicações mais complexas esta abordagem
pode não ser a mais correta. O mais aconselhável
é que se tenha um método responsável
por construir o objeto XMLHttpRequest e retorná-lo
ao chamador. Uma possível função seria:
function obterObjRequisicao(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}
else if(window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
}
return null;
}
Agora o objeto de requisição pode ser obtido
a partir de qualquer parte da aplicação:
// efetua uma chamada
à função obterObjRequisicao()
var http = obterObjRequisicao();
if(http){
// objeto XMLHttpRequest instanciado...pode usar
alert("Objeto XMLHttpRequest instanciado
com sucesso.");
}
Os próximos exemplos de código funcional disponível
neste artigo usam esta função para obter uma
instância do objeto de requisição.
1.2 - Propriedades e métodos do objeto XMLHttpRequest
Para obter o máximo das funcionalidades do objeto de
requisição, é preciso conhecer suas propriedades
e métodos principais. As tabelas a seguir facilitarão
este entendimento:
1.2.1 - Propriedades do objeto XMLHttpRequest
| Propriedade |
Descrição |
| onreadystatechange |
Um evento disparado a cada
vez que o estado da requisição sofre alterações.
Tal evento deve ser delegado a uma função
própria da aplicação sendo desenvolvida. |
| readyState |
Um
valor inteiro que permite monitorar o estado atual do
objeto de requisição. Possíveis
valores são:
- 0 – Objeto ainda não inicializado,
o método open() ainda não foi chamado;
- 1 – Carregando dados, o método send()
ainda não foi chamado;
- 2 – Dados carregados, o método send()
ainda não foi chamado mas os cabeçalhos
da resposta HTTP já estão disponíveis;
- 3 – Modo interativo, a propriedade responseText
já contém dados parciais;
- 4 – Operação concluída.
|
| responseText |
Resposta à requisição
em formato de texto puro |
| responseXML |
Resposta à requisição
em formato XML. Pode ser tratado como um objeto DOM Document. |
| status |
Código do status da
resposta, tal como 200 (OK), 505 (erro interno do servidor)
ou 404 (documento não encontrado). |
| statusText |
O texto associado ao status
da resposta HTTP. |
1.2.2 - Métodos do objeto XMLHttpRequest
| Método |
Descrição |
| abort() |
Cancela a requisição
HTTP. Não retorna nada |
| getAllResponseHeaders() |
Retorna
todos os cabeçalhos da resposta HTTP em formato
de texto pré-formatado. |
| getResponseHeader(string header) |
Retorna o valor do cabeçalho
especificado. |
| open(string method, string url,
string asynch) |
Prepara a requisição
HTTP, especifica o método usado (GET, POST, etc)
e se esta será ou não assíncrona.
Não retorna nada (void). |
| send(string) |
Envia a requisição
HTTP. Não retorna nada (void). |
| setHeader(string header, string
value) |
Permite definir um cabeçalho
de requisição. Deve ser chamado depois do
método open(). Não retorna nada (void). |
1.3 - O arquivo XML de testes
Para fins de demonstração das propriedades e métodos
do objeto XMLHttpRequest um arquivo XML se torna necessário.
O arquivo mostrado a seguir será usado para os exemplos
de códigos funcionais desta seção:
Código para alunos.xml
<?xml version="1.0"
encoding="iso-8859-1"?>
<alunos>
<aluno>
<nome>Osmar J. Silva</nome>
<matricula>547961-4</matricula>
</aluno>
<aluno>
<nome>Dyego Fernandes de Sousa</nome>
<matricula>545844-7</matricula>
</aluno>
<aluno>
<nome>Francisco Coelho Cito Feitosa</nome>
<matricula>768212-3</matricula>
</aluno>
</alunos>
Para sua comodidade, este arquivo XML está disponível
aqui.
1.4 - Efetuando uma requisição usando
XMLHttpRequest
Uma vez entendidas as propriedades e métodos do objeto
de requisição, os códigos que efetuam a
requisição ao servidor web e obtém os resultados
a serem analisados podem ser escritos sem maiores dificuldades.
A listagem seguinte mostra como ler o conteúdo do arquivo
XML apresentado no tópico 1.3 e apresentá-lo em
uma caixa de mensagem:
<script language="javascript">
<!--
// efetua uma chamada à função
obterObjRequisicao()
var http = obterObjRequisicao();
if(http){
var url = "http://www.arquivodecodigos.net/arquivo/alunos.xml";
http.onreadystatechange = processar;
http.open("GET", url, true);
http.send(null);
}
function processar(){
if(http.readyState == 4){
if(http.status == 200){
window.alert(http.responseText);
}
}
}
//-->
</script>
Obs: Muitos iniciantes em AJAX enfrentam um
erro muito comum ao tentarem executar uma requisição
local usando o objeto XMLHttpRequest. Saiba desde já
que não funciona. Para que a requisição
seja feita com sucesso, o arquivo XML precisa estar em um servidor
web e ser requisitado via HTTP.
Este trecho de código, quando executado, gera um resultado
semelhante ao mostrado na figura a seguir:

Quer experimentar? Clique
aqui para ver o exemplo funcionando.
Obs: O objeto XMLHttpRequest não permite
requisições para domínios diferentes daquele
em que a página HTML está. Nosso site pode ser
acessado por dois domínios: www.recomende.com e www.arquivodecodigos.net.
Se o domínio for www.recomende.com, o link acima não
possibilitará ver o exemplo funcionando corretamente.
A descrição do erro apresentado é "Acesso
negado".
Este código é a base para o perfeito entendimento
das requisições usando XMLHttpRequest. Assim,
uma análise cuidadosa dos passos envolvidos deve ser
feita. Começando com a linha:
// efetua uma chamada
à função obterObjRequisicao()
var http = obterObjRequisicao();
Aqui um objeto de requisição é obtido a
partir de uma chamada ao método obterObjRequisicao().
Esta função foi apresentada na seção
1.1. O trecho seguinte:
if(http){
var url = "http://www.arquivodecodigos.net/arquivo/alunos.xml";
http.onreadystatechange = processar;
http.open("GET", url, true);
http.send(null);
}
Testa se a variável http representa
um objeto de requisição válido. Caso este
teste retorne verdadeiro um bloco de códigos importantes
é executado. A linha:
var url = "http://www.arquivodecodigos.net/arquivo/alunos.xml";
define o endereço do documento a ser acessado. A título
de estudo, o documento usado é um simples arquivo XML.
Em aplicações do mundo real, o endereço
poderia ser uma página dinâmica que faria uma conexão
com bancos de dados, por exemplo.
A linha:
http.onreadystatechange
= processar;
define o método que será chamado todas as vezes
que o evento onreadystatechange do objeto de requisição
for disparado. A linha:
http.open("GET",
url, true);
efetua uma chamada à função open fornecendo
o método de requisição (que pode ser GET,
POST, HEAD, etc), o endereço do documento a ser acessado
e define se a chamada será síncrona ou assíncrona.
O valor true indica assíncrona. Finalmente a linha:
http.send(null);
permite enviar parâmetros de requisição
ao servidor. Quando o método GET é usado, o valor
null deve ser definido.
O ponto de partida para o processamento das informações
recebidas em resposta à requisição está
dentro da função delegada ao evento onreadystatechange:
function processar(){
if(http.readyState == 4){
if(http.status == 200){
window.alert(http.responseText);
}
}
}
Aqui o estado é testado para verificar se a requisição
está completa. Se estiver, o status do objeto de requisição
é testado também. O valor 200 indica que se obteve
sucesso. Para exibir o conteúdo do arquivo XML, a propriedade
responseText é usada. É sempre uma boa idéia
informar o usuário da aplicação de alguma
falha, ou seja, tomar alguma providência quando o documento
solicitado não puder ser encontrado. Assim, a função
anterior poderia ser entendida para esta nova versão:
function processar(){
if(http.readyState == 4){
if(http.status == 200){
window.alert(http.responseText);
}
else{
window.alert("Erro!
Documento não encontrado.");
}
}
}
1.5 - Apresentando o XML DOM
O tópico 1.4 mostrou como é possível obter
um arquivo XML como resposta a uma requisição
HTTP usando o objeto XMLHttpRequest. No entanto, se as informações
contidas no arquivo XML não puderem ser processadas adequadamente,
todo o esforço será em vão.
O Modelo de Objetos de Documentos XML (XML DOM) define uma forma
padrão para o acesso e manipulação das
informações contidas em um documento XML. Desta
forma, o documento XML é apresentado como uma estrutura
semelhante a uma árvore, onde os elementos, atributos
e valores são definidos como nós.
O primeiro passo para acessar o XML DOM é obter uma representação
a partir da resposta enviada ao objeto de requisição.
Isso pode ser feita da seguinte forma:
function processar(){
var docXML;
if(http.readyState == 4){
if(http.status == 200){
docXML = http.responseXML;
window.alert(docXML.documentElement.nodeName);
}
else{
window.alert("Erro!
Documento não encontrado.");
}
}
}
Esta é uma pequena variação da função
processar vista em tópicos anteriores. As alterações
mais visíveis são:
var docXML;
define a variável que representará o documento
XML. Tal documento é obtido na linha:
docXML = http.responseXML;
A partir daí o objeto docXML contém um documento
XML pronto para ser acessado e manipulado. Um exemplo bem simples
é:
window.alert(docXML.documentElement.nodeName);
Esta instrução gera a exibição da
seguinte mensagem:

Esta mensagem exibe o nome do elemento principal do documento
XML alunos.xml.
Assim, tal documento pode ser exibido, em termos de XML DOM,
da seguinte forma:
Este diagrama mostra que é possível acessar os
elementos de um documento XML usando a hierarquia pai-filhos-irmãos.
Por exemplo, se é fato que o elemento principal do documento
pode ser acessado usando:
docXML.documentElement;
então seu primeiro filho nos levaria ao elemento aluno:
docXML.documentElement.childNodes[0];
Então, o valor do elemento nome do primeiro elemento
aluno pode ser acessado assim:
docXML.documentElement.childNodes[0].childNodes[0].
childNodes[0].nodeValue;
O seguinte trecho de código mostra como é possível
acessar todos os elementos do documento alunos.xml e exibi-los
em uma tabela HTML:
function processar(){
var docXML;
if(http.readyState == 4){
if(http.status == 200){
docXML = http.responseXML;
montarTabela(docXML);
}
else{
window.alert("Erro!
Documento não encontrado.");
}
}
}
function montarTabela(xml){
var doc = xml.documentElement;
document.write("<table border='1'>");
for(var i = 0; i < doc.childNodes.length; i++){
document.write("<tr>");
document.write("<td>"
+ doc.childNodes[i].childNodes[0]. 
childNodes[0].nodeValue
+ "</td>");
document.write("<td>"
+ doc.childNodes[i].childNodes[1]. 
childNodes[0].nodeValue
+ "</td>");
document.write("</tr>");
}
document.write("</table>");
}
A execução deste trecho de código produzirá
o seguinte resultado:
Quer experimentar? Clique
aqui e veja este exemplo em funcionamento (certifique-se
de que está acessando este artigo a partir do domínio
www.arquivodecodigos.net).
1.6 - Navegando pelos nós do XML DOM
A navegação pelos nós do XML DOM
pode ser feita usando o relacionamento entre eles. Uma descrição
deste relacionamento é apresentada a seguir:
| Elemento |
Descrição |
| parentNode |
Retorna o nó pai
de um determinado elemento |
| childNodes |
Retorna
uma lista de nós contendo todos os filhos do
nó selecionado |
| firstChild |
Retorna o primeiro filho do
elemento selecionado. |
| lastChild |
Retorna o último filho
do elemento selecionado. |
| nextSibling |
Retorna o próximo elemento
irmão, ou seja, aquele no mesmo nível da
árvore. |
| previousSibling |
Retorna o irmão anterior,
ou seja, o nó anterior no mesmo nível da
árvore. |
Um bom uso para a propriedade childNodes é
quando se precisa obter a quantidade de nós filhos que
um nó pai contem. O trecho de código a seguir
mostra como isso pode ser feito:
...
docXML = http.responseXML;
window.alert(docXML.documentElement.childNodes.length);
...
1.7 - Obtendo uma lista de nós através
do método getElementsByTagName
O XML DOM oferece uma forma muito conveniente de se obter apenas
um determinado grupo de elementos: o método getElementsByTagName.
Este método retorna uma matriz de nós cujos nomes
de tags coincidem com aquele fornecido como argumento para o
método. O trecho de código a seguir mostra como
é possível efetuar um atalho no documento XML
usado como exemplo para obter apenas os nós que contém
as matrículas dos alunos:
docXML = http.responseXML;
var elem = docXML.getElementsByTagName("matricula");
for(var i = 0; i < elem.length; i++){
document.write(elem[i].childNodes[0].nodeValue +
"<br>");
}
Este código, ao ser executado, produzirá o resultado:
547961-4
545844-7
768212-3 |