Percorrendo um arquivo XML em Java com dom4j

{lang: 'pt-BR'}

Existem inúmeras maneiras de percorrer um arquivo XML usando Java, um processo que chamamos de parser xml. Um amigo meu levantou que é muito mais simples manipular um arquivo XML usando Python do que Java. De uma forma geral é verdade, mas isso não quer dizer que não seja possível fazer usar recursos simples no Java também.

A biblioteca que irei usar é a http://dom4j.sourceforge.net/. Eu criei um projeto Maven que resolveu a dependência para mim:


   dom4j
   dom4j
   1.6.1

O xml que usei para testes, é uma simples listagem de notas de alunos:

	

	
		Joao
		7
		8
		5
		10
	
 
	
		Maria
		8
		6
		6
		9
	
 
	
		Jose
		5
		6
		4
		5
	

Ao contrário das APIs nativas do Java (SAX e DOM), o dom4j exige uma codificação mais simples, menos verboso (odeio essa palavra). A idéia é que possamos manipular o xml como se estivéssemos manipulando uma árvore de uma maneira bem natural, passando por nós e seus filhos.

Abrir um arquivo XML local:

SAXReader reader = new SAXReader();
Document doc = reader.read("teste.xml");

Simples assim. Se você quisesse abrir um arquivo remoto disponível na web, tudo bem:

SAXReader reader = new SAXReader();
Document doc = reader.read("http://www.google.com/sitemap.xml");

Para percorrer as notas de alunos, primeiro devemos obter o nó raiz <alunos> e em seguida navegar por seus nós filhos <aluno>. Para cada filho, buscamos os nós de nome e notas.

Element root = doc.getRootElement();
for ( Object studentObj : root.elements()) {
	Element studentElement = (Element) studentObj;
	System.out.println("---------");
	System.out.println("Nome: "+studentElement.element("nome").getText());
	System.out.println("Nota 1: "+studentElement.element("nota1").getText());
	System.out.println("Nota 2: "+studentElement.element("nota2").getText());
	System.out.println("Nota 3: "+studentElement.element("nota3").getText());
	System.out.println("Nota 4: "+studentElement.element("nota4").getText());
}

O código acima irá gerar a seguinte saída:

---------
Nome: Joao
Nota 1: 7
Nota 2: 8
Nota 3: 5
Nota 4: 10
---------
Nome: Maria
Nota 1: 8
Nota 2: 6
Nota 3: 6
Nota 4: 9
---------
Nome: Jose
Nota 1: 5
Nota 2: 6
Nota 3: 4
Nota 4: 5

Aproveitando a oportunidade, aproveitei para fazer um comparativo de código e performance do dom4j e da implementação nativa DOM. Usei como exemplo o sitemap fornecido pelo Google, que tem este formato:


  
    http://www.google.com/
    1.000
  
  
    http://www.google.com/3dwh_dmca.html
    0.5000
  

Usando dom4J:

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

SAXReader reader = new SAXReader();
Document doc = reader.read(filename);

Element root = doc.getRootElement();
StringBuffer sb = new StringBuffer();
for ( Object obj : root.elements()) {
	Element urlElement = (Element) obj;
	sb.setLength(0);
	sb.append(urlElement.elementText("loc"))
	   .append(" (").append(urlElement.elementText("priority")).append(")");
	sb.toString(); // do not print, just process
}

usando DOM:

import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Node;

File xmlFile = new File(filename);
org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance()
		.newDocumentBuilder().parse(xmlFile);
doc.getDocumentElement().normalize();

printMemory("Depois de abrir o arquivo");

StringBuffer sb = new StringBuffer();
Node urlset = doc.getFirstChild();
Node content;
String url = null, priority = null;
for (Node urlNode = urlset.getFirstChild(); 
		urlNode != null; 
		urlNode = urlNode.getNextSibling()) {

	urlNode.getFirstChild();
	if (urlNode.getNodeType() == Node.ELEMENT_NODE) {
		for (content = urlNode.getFirstChild(); 
				content != null; 
				content = content.getNextSibling()) {

			if (content.getNodeName().equals("loc")) {
				url = content.getTextContent();
			} else if (content.getNodeName().equals("priority")) {
				priority = content.getTextContent();
			}
		}
		sb.setLength(0);
		sb.append(url).append(" (").append(priority).append(")");
		sb.toString();
	}
}

De cara dá para ver que o código DOM exige muito mais linhas que o código usando dom4j. Além da chateação de escrever mais, o código também possui uma lógica estranha, pois espaços em brancos entre um nó XML e outro, também são considerados um nó.

chart_2

Em princípio, a API DOM é ligeiramente mais eficiente que o dom4j para arquivos menores. Já para arquivos grandes (aprox. 100Mb) o dom4j leva vantagem.

No quesito consumo de memória, o dom4j também tem um desempenho melhor. O consumo de memória ficou menor em todos os casos. De qualquer forma, fique alerta de que ao abrir um arquivo XML você precisará de 7 a 11 vezes o tamanho do arquivo em memória.

{lang: 'pt-BR'}
  • werneckpaiva

    Vale fazer um comparativo com a API Python.

  • Eliandro Borges

    Cara! Muito obrigado por disponibilizar um conteúdo desta qualidade! Enfim consegui executar uma tarefa que estava precisando! Obrigado MESMO!