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

07 May 2009
5 mins read

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

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

Para este post, vamos utilizar este XML como exemplo:

dom05

Para trabalhar com a informação de um arquivo XML, é ncessário primeiro fazer o parse para criar um objeto Document. Como o objeto Document é uma interface, não podemos instanciar diretamente. Geralmente, utilizamos uma Factory. O processo exato pode variar de implementação para implementação, mas as idéias são as mesmas.

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

javatechandxml_illus4

Os três passos em um ambiente java são:

  1. - Criar um DocumentBuilderFactory: este objeto cria um DocumentBuilder
  2. Criar um DocumentBuilder: este objeto faz o parse para criar um objeto do tipo Document
  3. Parsear o arquivo para criar um objeto Document.

[code lang="java"]
//fazer o parse do arquivo e criar o documento XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(arquivoXML);
[/code]

Uma vez que o é feito o parse do documento e o objeto Document é criado, a aplicação pode explorar a estrutura da árvore XML, exibindo a informação na tela, guardando os dados em um objeto, etc.
Todo documento XML inicia-se pelo elemento raiz. Um documento XML bem formado possui apenas um elemento raiz, também conhecido como DocumentElement. Então, o primeiro passo é a nossa aplicação obter esse elemento.

[code lang="java"]
//Passo 1: obter o elemento raiz
Element raiz = doc.getDocumentElement();
System.out.println("O elemento raiz é: " + raiz.getNodeName());
[/code]

Após a determinação do element raiz, podemos obter a lista de elementos filhos. O DOM fornece um tipo especial de interface de coleção chamada NodeList usada para referenciar uma lista de referências do tipo Node. Ou seja, sempre que desejarmos obter os filhos de um elemento, devemos utilizar esse método, mesmo sabendo que este determinado elemento possui apenas 1 subelemento.

Vamos obter agora os elementos do tipo contato:

[code lang="java"]
//Passo 2: localizar os elementos filhos da agenda
NodeList listaContatos = raiz.getElementsByTagName("contato");
[/code]

Como temos uma coleção de elementos contato, vamos percorrer cada um deles para obter as informações que queremos:

[code lang="java"]
//Passo 3: obter os elementos de cada elemento contato
for (int i=0; i<listaContatos.getLength(); i++){

//como cada elemento do NodeList é um nó, precisamos fazer o cast
Element contato = (Element) listaContatos.item(i);
[/code]

Agora que já temos acesso ao elemento contato, vamos começar a extrair as informações. Nosso primeiro passo é obter o valor do atributo id:

[code lang="java"]
//Passo 4: obter o atributo id do contato
Attr id = contato.getAttributeNode("id");
System.out.println("Contato id: " + id.getNodeValue());
[/code]

Após obtermos o atributo, vamos começar a extrair as informações dos elementos do contato. Para isso, vamos obter um NodeList com os elementos do tipo 'nome'. Como sabemos que o arquivo XML tem apenas um elemento do tipo nome para cada elemento do tipo contato, podemos fazer referência diretamente para o primeiro elemento dessa lista. Como visto no post passado, um nó do tipo elemento possui valor null, então não podemos pegar diretamente o valor desse nó, temos que pegar o valor do nó texto, que obtemos através do método getFirstChild():

[code lang="java"]
//Passo 5: obtém o nome do contato
NodeList listaNomes = contato.getElementsByTagName("nome");
Node nome = listaNomes.item(0).getFirstChild();
System.out.println("Nome: " + nome.getNodeValue());
[/code]

Fazemos isso para cada informação que desejamos extrair: endereco, telefone e email. Apenas precisamos modificar a String passada como argumento pelo método getElementsByTagName. Fica assim:

[code lang="java"]
//Passo 6: obtém o endereço do contato
NodeList listaEndereco = contato.getElementsByTagName("endereco");
Node endereco = listaEndereco.item(0).getFirstChild();
System.out.println("Endereço: " + endereco.getNodeValue());

//Passo 7: obtém o telefone do contato
NodeList listaTelefone = contato.getElementsByTagName("telefone");
Node telefone = listaTelefone.item(0).getFirstChild();
System.out.println("Telefone: " + telefone.getNodeValue());

//Passo 8: obtém o email do contato
NodeList listaEmail = contato.getElementsByTagName("email");
Node email = listaEmail.item(0).getFirstChild();
System.out.println("Email: " + email.getNodeValue());
[/code]

E acabamos de extrair todas as informações do XML!

O código de parsing também precisa considerar a captura de erros de exceção para reportar os vários erros que podem acontecer, como por exemplo:

Todo o código acima está dentro de um bloco try-catch:

[code lang="java"]
} catch (ParserConfigurationException e) {
System.out.println("O parser não foi configurado corretamente.");
e.printStackTrace();
} catch (SAXException e) {
System.out.println("Problema ao fazer o parse do arquivo.");
e.printStackTrace();
} catch (IOException e) {
System.out.println("O arquivo não pode ser lido.");
e.printStackTrace();
}
[/code]

Podemos melhorar o código na hora de obter as informações do contato, criando um método genérico para extrair o valor de uma tag específica:

[code lang="java"]
public String obterValorElemento(Element elemento, String nomeElemento){
//obtém a lista de elementos
NodeList listaElemento = elemento.getElementsByTagName(nomeElemento);
if (listaElemento == null){
return null;
}
//obtém o elemento
Element noElemento = (Element) listaElemento.item(0);
if (noElemento == null){
return null;
}
//obtém o nó com a informação
Node no = noElemento.getFirstChild();
return no.getNodeValue();
}
[/code]

Podemos melhorar mais ainda construindo um código que retorne uma lista de objetos do tipo Contato. Para isso, precisamos também contruir uma classe do tipo Contato:

[code lang="java"]
public class Contato {

private int id;
private String nome;
private String endereco;
private String telefone;
private String email;

//métodos getters e setters
}
[/code]

O método:

[code lang="java"]
public Contato criaContato(Element elemento){
Contato contato = new Contato();
contato.setId(Integer.parseInt(elemento.getAttributeNode("id").getNodeValue()));
contato.setNome(obterValorElemento(elemento,"nome"));
contato.setEndereco(obterValorElemento(elemento,"endereco"));
contato.setTelefone(obterValorElemento(elemento,"telefone"));
contato.setEmail(obterValorElemento(elemento,"email"));
return contato;
}
[/code]

E nosso novo código:

[code lang="java"]
//Passo 3: obter os elementos de cada elemento contato
for (int i=0; i<listaContatos.getLength(); i++){

//como cada elemento do NodeList é um nó, precisamos fazer o cast
Element elementoContato = (Element) listaContatos.item(i);

//cria um objeto Contato com as informações do elemento contato
Contato contato = criaContato(elementoContato);
System.out.println(contato);
}
[/code]

O código completo desse post você pode fazer o download aqui (projeto no formato da IDE Eclipse, compilado com Java 5):

download

Até a próxima!

No proximo post sobre esta série, um passo a passo de como modificar um XML utilizando a API DOM.

Até a próxima!

:)