Manipulando arquivos XML em Java com a API SAX - Parte II

22 May 2009
2 mins read

No post anterior, você viu como funcionar a API SAX do Java.

Neste post você irá aprender como ler um documento XML utilizando a interface SAX.
Para isso, você irá precisar:

* JDK 1.4 ou superior
* Editor de texto ou uma IDE Java de sua escolha

Para este post, vamos utilizar este XML como exemplo:
dom05

A figura abaixo exemplifica o processo de parsear um XML com a API SAX (fonte: SUN):
javatechandxml_illus3

O processo é bem parecido com a API DOM, ou seja, com apenas 3 passos, podemos ler um arquivo XML:

1.Criar um SAXParserFactory: este objeto cria um SAXParser
2. Criar um SAXParser: este objeto faz o parse
3. Parsear o arquivo; e o resto é "automático" (dispara os eventos).

[code lang="java"]
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
parser.parse("contato.xml", this );
[/code]

Agora, precisamos os método para tratar os eventos:

Primeiro vamos criar o método startDocument. Vamos apenas mostrar uma mensagem que o parse começou a ler o arquivo XML:
[code lang="java"]
public void startDocument() {
System.out.println("Iniciando a leitura do XML");
}
[/code]

Vamos criar também o método endDocument, que mostra quando o parse terminou de ler o arquivo XML:
[code lang="java"]
public void endDocument() {
System.out.println("Acabou a leitura do XML");
}
[/code]

Agora, vamos criar o método que trata quando o parser encontra a abertura de uma tag. Vamos aproveitar e guardar as infomações encontradas em um objeto do tipo contato, para possível uso futuro. Além disso, vamos imprimir as informações encontradas no console:
[code lang="java"]
public void startElement(String uri, String localName, String tag, Attributes atributos){

//cria um contato
if (tag.equalsIgnoreCase(NO_CONTATO)){
contatoTemp = new Contato();
}

//imprime o caminho da tag
System.out.print("\n" + tag + ": ");

//se o elemento possui atributos, imprime
for (int i=0; i< atributos.getLength(); i++){
System.out.print(" " + atributos.getQName(i) + "=" + atributos.getValue(i));
if (atributos.getQName(i).equalsIgnoreCase(ATT_ID)){
contatoTemp.setId(Integer.parseInt(atributos.getValue(i)));
} else if (atributos.getQName(i).equalsIgnoreCase(ATT_GRAVADO)){
contatoTemp.setGravado(atributos.getValue(i));
}
}

}
[/code]

Vamos criar também o método que trata quando o parser encontra o final de uma tag. No caso do exemplo utilizado, quando encontramos o final de uma tag (exceto a tag contato), significa que já temos uma informação coletada, então vamos guardar essa informação no atributo do objeto Contato, e após guardar essa informação, vamos limpar o buffer para que este possa coletar uma nova informação. Se o parser encontrar o final da tag contato (), significa que o objeto já possui todas as informações necessárias, então vamos adicioná-lo numa lista de contatos:
[code lang="java"]
public void endElement(String uri, String localName, String tag){

//adiciona o contato na lista
if (tag.equalsIgnoreCase(NO_CONTATO)){
contatos.add(contatoTemp);
System.out.println();
}
//senão, seta os atributos do contato
else if (tag.equalsIgnoreCase(NO_NOME)){
contatoTemp.setNome(valorAtual.toString().trim());
} else if (tag.equalsIgnoreCase(NO_ENDERECO)){
contatoTemp.setEndereco(valorAtual.toString().trim());
} else if (tag.equalsIgnoreCase(NO_TELEFONE)){
contatoTemp.setTelefone(valorAtual.toString().trim());
} else if (tag.equalsIgnoreCase(NO_EMAIL)){
contatoTemp.setEmail(valorAtual.toString().trim());
}

//limpa o valor Atual
valorAtual.delete(0, valorAtual.length());
}
[/code]

E por último, vamos criar o método que trata quando algum caracter ou informação é encontrada pelo parser. Como este método pode ser chamado algumas vezes pelo parser, vamos guardar a informação encontrada no buffer, que assim que terminar (encontrar o final de uma tag), poderemos utilizar essa informação, como visto no método acima declarado.
[code lang="java"]
public void characters(char[] ch, int start, int length) {
System.out.print(String.copyValueOf(ch,start,length).trim());

valorAtual.append(ch,start,length);

}
[/code]

Viu como é simples? O importante é guardar a informação à medida que for reconhecida pelo parser, pois, se perder alguma informação, náo tem como voltar atrás, como na árvore DOM.

O código completo desse post você pode fazer o download aqui (formato projeto Eclipse)
download

Até a próxima!

Nos vemos no Falando em Java 2009, dia 24 de maio (próximo domingo) em São Paulo! :)