Lendo XML com Groovy (ou como causar inveja em um programador Java (e depois satisfazê-la!)) – (ou ainda, como ler XML SEMPRE deveria ter sido)

Sempre achei XML paradoxal. Por um lado, trata-se de uma tecnologia fantástica: a sintaxe do XML é simplíssima. Qualquer um consegue gerar um documento no formato XML. No entanto, em contrapartida, ler o bem dito documento (ao menos em Java) pode ser um suplício.

Há ferramentas que facilitam este trabalho (Dom4J, XStreamer, etc.), mas é uma pena que, na própria linguagem, nativamente, tais recursos não existam (é compreensível, mas é chato). Sendo assim, gostaria de incluir mais uma ferramenta para facilitar a vida do desenvolvedor Java: Groovy! Neste post (que pode ser considerado uma continuação do anterior), irei mostrar como se parseia um documento XML usando Groovy em, em seguida, como integrar este parser em seu código Java (satisfaço assim a sua inveja).

Para começar, iniciemos com o documento XML que iremos parsear:

<?xml encoding="ISO-8859-1" version="1.0"?>
<enderecos>
    <endereco id="1">
        <rua>Paraíba</rua>
        <numero>1061</numero>
        <bairro>Savassi</bairro>
        <cidade>Belo Horizonte</cidade>
    </endereco>
    <endereco id="2">
        <rua>Av. Afonso Pena</rua>
        <numero>4114</numero>
        <bairro>Cruzeiro</bairro>
        <cidade>Belo Horizonte</cidade>
    </endereco>
</enderecos>

E, o código feito em Groovy para parsear este XML é…

def registros = new XmlParser().parseText(str)
def enderecos = registros.endereco.size()
for (int i = 0; i < registros.endereco.size(); i++) {
    print "\n${registros.endereco&#91;i&#93;.'@id'}"
    print "\n\t${registros.endereco&#91;i&#93;.rua.text()}"
    print "\n\t${registros.endereco&#91;i&#93;.numero.text()}"
    print "\n\t${registros.endereco&#91;i&#93;.bairro.text()}"
    print "\n\t${registros.endereco&#91;i&#93;.cidade.text()}"
}
&#91;/code&#93;
Agora, vamos comentar este código linha a linha: primeiro, iremos comentar a <i>não linha</i> deste código. Repare que não há instrução alguma de importação de classes ou pacotes. Isto porque a classe XmlParser se trata de um recurso nativo da linguagem.

def registros = new XmlParser().parseText(str)

É declarada aqui uma variável chamada registros, que é o resultado da função parseText do objeto XmlParser, que acabamos de instanciar. Este método recebe como parâmetro apenas uma string (no caso, imaginemos que exista uma variável chamada str em nosso código fonte, que contenha o XML descrito acima). registros consiste em uma Collection, que armazena objetos cujos métodos e atributos serão definidos de acordo com o conteúdo do XML parseado.


(
Já se perguntou pra que serve este lance de ficar incluindo métodos e atributos em uma classe em tempo de execução? Eis aqui um bom exemplo.
O objeto retornado pelo Parser possuirá métodos e atributos definidos de acordo com o XML parseado! Veja o código abaixo:

)

def enderecos = registros.endereco.size()

O objeto enderecos representa o elemento raiz do XML lido. Como o XML lido possui mais de um elemento endereco, Groovy o trata como uma coleção. Então, chama-se o método size desta coleção para se saber quantos endereços estão armazenados na estrutura registros.

Dentro do loop, fica ainda mais nítido como acessar estes valores a partir do XML:

print "\n${registros.endereco[i].'@id'}"

Em cada objeto do tipo endereco (criado dinâmicamente por Groovy), imprimo o atributo id do mesmo. Faço isto usando o operador @id.

O operador @[nome do atributo] consiste em um construtor do Groovy que nos permite acessar diretamente um atributo de determinado objeto. Groovy criou um atributo chamado id na classe endereco. Sacou? id era um atributo do elemento endereco no XML. Logo, vira um atributo da classe endereco criada dinâmicamente!

print "\n\t${registros.endereco[i].rua.text()}"

Aqui, percebe-se que foi criado um objeto chamado rua dentro da estrutura do objeto endereco. Como trata-se de um elemento XML, Groovy o transforma em outro objeto! Para saber o seu conteúdo, simplesmente chamo a função text() deste objeto criado.

Como pode-se observar (não vou ficar repetindo as últimas linhas do código), o modo como o Groovy parseia o XML é muito simples. É criado um código muito mais fácil de entender do que aquele que estamos acostumados a trabalhar com Java (ou C#). Nada de NodeLists, Elements, etc. Os elementos do XML recebem nomes que correspondem aquilo representado no documento. Seu cliente poderia ler este código e compreendê-lo sem problemas (pense nisto).

Então, agora que criei inveja em programadores que trabalhem com Java, vou sacia-la. Código Groovy é 100% integrado ao código Java. Um chama o outro sem a menor dificuldade. Sendo assim, segue abaixo uma classe, escrita em Java, que expõe como integrar seu código Java com Groovy :)

import java.io.IOException;
import java.util.List;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;


public class EnderecoParser {
    
    // GroovyShell é a classe responsável por executar código Groovy
    private static GroovyShell shell;
    // Binding passa parâmetros ao seu código Groovy
    private static Binding binding = new Binding();
    // Script corresponde ao seu código fonte
    private static Script script;
    
    /* Função que retorna o código fonte do Groovy 
        Pega o código fonte que esteja no classpath da aplicação*/
    private String getCodigoFonte() throws IOException {
        InputStream streamEntrada = getClass().getClassLoader().getResourceAsStream("EnderecoParser.groovy");
        if (streamEntrada != null) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(streamEntrada));
            String str = null;
            StringBuilder builder = new StringBuilder();
            while ((str = reader.readLine()) != null) {
                builder.append(str).append("\n");
            }
            reader.close();
            return builder.toString();
        }
        return null;
    }
    // Recebo como parametro o XML armazenado em uma String
    public List getActions(String str) throws IOException {
        if (str != null) {
           // Passo esta variável ao meu script groovy (o mesmo código que citei acima!)
            binding.setVariable("str", str);
            if (shell == null) {
                shell = new GroovyShell(binding);
                script = shell.parse(getCodigoFonte());
            }
           /*
                     Eu poderia ter uma classe chamada Endereco, que é populada com os dados do XML
                     pelo próprio parser.
            */
              return  (List) script.run();
          }
        return null;
    }
}

15 comments on “Lendo XML com Groovy (ou como causar inveja em um programador Java (e depois satisfazê-la!)) – (ou ainda, como ler XML SEMPRE deveria ter sido)

  1. Inocencio

    Sem dúvida, o Groovy dispõe de melhores consideráveis, comecei a pouco tempo dar uma olhada nessa linguagem.

    Para Java puro existe um framework para trabalhar com XML que achei melhor do que as conhecidas opções como XStream e Dom4j é o: Simple XML.

    Vale a pena dar uma conferida: http://simple.sourceforge.net/

    Responda

  2. Lou

    errr, é uma dúvida meio noob, mas o método sempre retorna null, não entendo por que, o resto ele faz direitinho, imprime as coisas na tela e tudo mais

    Responda

    admin Reply:

    Qual método? Como foi implementado? Entre em contato comigo por msn ou e-mail para que a gente possa discutir o assunto, ok?

    Responda

  3. Dalto Curvelano

    Kiko, tanto o hpricot quanto o nokogiri também funcionam com XML.
    O nokogiri usa a libxml2 e é bem rápido.

    []’s

    Responda

    admin Reply:

    Opa. Sabia desta não. Bom saber! Valeu!

    Responda

  4. Beto

    Olá Kico,

    Atualmente tenho centenas de xml’s que gostaria de ler somente o conteúdo de seus respctivos campos e depois printalos em um arquivo txt. Pode me ajudar?

    Abçs

    Responda

    admin Reply:

    Uai Beto, assim de cara não sei te responder. Se quiser, pode me contactar por msn ou talk pra que a gente veja o que pode ser feito ok?

    Responda

  5. wander arce

    Bom dia galera!!!!

    Tenho uma dúvida, preciso envolver tratamento de arquivo em uma aplicação tendo em vista a importação de arquivos (XML, Excel e CVS) para gerar um formulario ou uma base de dados e exportação(PDF, Excel, CVS, XML , JPG, PNG) para gerar relatorios, tabelas, gráficos ou figuras, alguém pode indicar um plugin mais completo, já pesquisei pelo ExtJs, Primefaces, entre outros.

    Atenciosamente,

    Wander Arce

    Responda

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.