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

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:

  • 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

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.
//fazer o parse do arquivo e criar o documento XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(arquivoXML);

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.

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

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:

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

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

//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);

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:

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

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():

//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());

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:

//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());

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:

  • ParserConfigurationException – acionado quando o DocumentBuilderFactory não consegue criar o parser.
  • SaxParseException – ocorrendo quando o parser encontra um problema na formatação do arquivo XML. O objeto Exception carrega informações sobre a localização do erro no arquivo.
  • IOException – Acionado quando um erro de arquivo ocorre.

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

} 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();
}

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:

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();
}

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:

public class Contato {

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

//métodos getters e setters
}

O método:

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;
}

E nosso novo código:

//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);
}

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!

:)

Posts Similares

Filed Under: JavaXML

Tags: , , , ,

About the Author

Bacharel em Ciência da Computação, trabalha como Senior Software Engineer/Tech Leader no Citibank (maior instituição financeira do mundo), em São Paulo. Autora do livro ExtJS 4 First Look, publicado mundialmente pela editora Packt Publishing. Possui um blog em inglês (http://loianegroner.com) e também contribui com artigos em inglês para o Java Lobby do portal DZone. JUG leader do CampinasJUG/Java Campinas, coordenadora do ESJUG e uma das fundadoras do JDuchessBR.

Comments (10)

Trackback URL | Comments RSS Feed

  1. [...] series Java e XMLJava e XMLJava e XMLManipulando arquivos XML em Java com a API DOM – Parte IManipulando arquivos XML em Java com a API DOM – Parte IIManipulando arquivos XML em Java com a API DOM – Parte IIIManipulando arquivos XML em Java com [...]

  2. [...] Manipulando arquivos XML em Java com a API DOM – Parte II [...]

  3. Muito bom Loiane!

    Me ajudou bastante em um problema com Webservices e XML, realmente bacana. Parabéns!

  4. Fred says:

    Estou tendo um erro na linha db.parse(arquivoXml) que é o seguinte:
    A pseudo attribute name is expected

    Não achei em lugar algum alguem com o mesmo erro e a solução. O que pode ser??
    Obrigado

  5. Fred says:

    faltava o ?> pra fechar meu xml hehe
    ja deu certo…desuclpe ai

  6. Bruno Baudel says:

    Meu amigo voce me ajudou muito com esse tutorial gostei da linguagem que foi utilizada simples e eficaz

    parabens

  7. Loiane

    Parabéns pelo post, é o único que realmente explica como manipular corretamente o XML.

    Baixei seu projeto e coloquei pra rodar sem problemas. Até testei com um XML que tenho e o parser foi executado sem problemas.
    Entranto quando coloco o trecho do parser na minha aplicação web recebo essa exceção:

    14:57:32,675 INFO [STDOUT] java.io.UTFDataFormatException: Invalid byte 2 of 2-byte UTF-8 sequence.
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.io.UTF8Reader.invalidByte(Unknown Source)
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.io.UTF8Reader.read(Unknown Source)
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.XMLEntityScanner.load(Unknown Source)
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.XMLEntityScanner.scanContent(Unknown Source)
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanContent(Unknown Source)
    14:57:32,676 INFO [STDOUT] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    14:57:32,677 INFO [STDOUT] at org.jdom.input.SAXBuilder.build(SAXBuilder.java:489)
    14:57:32,677 INFO [STDOUT] at org.jdom.input.SAXBuilder.build(SAXBuilder.java:847)
    14:57:32,677 INFO [STDOUT] at org.jdom.input.SAXBuilder.build(SAXBuilder.java:826)

    Estou usando o JBoss 4.0.2 e acredito que ele está tentando fazer o parser com a biblioteca xercesImpl que está na pasta de libs do JBoss (C:/jboss-4.0.2/lib/endorsed/). Já tentei remover a biblioteca, mas surgem vários outros problemas.

    Você sabe alguma forma de ignorar estas bibliotecas para que possa usar as nativas do Java?

    Obrigada ;)

  8. Loiane says:

    Ixi Brena, não sei, nunca tive esse problema.
    Conferiu os imports pra ver se é o mesmo?

  9. Ei Loiane
    Agora estou utilizando a biblioteca soap-2.3.1.jar e faço o parser desta forma:

    DocumentBuilder db = XMLParserUtils.getXMLDocBuilder();
    ByteArrayInputStream bais = new ByteArrayInputStream(conteudoArquivo.toString().getBytes(“UTF-8″));
    Document doc = db.parse(new InputSource(bais));

    Obrigada ;)

  10. Desiree says:

    Parabéns pelo post . Bem detalhado !!!

Leave a Reply




If you want a picture to show with your comment, go get a Gravatar.