Lendo um arquivo XML com XPath

Author PerlBrasil Category , ,

A leitura de arquivos XML não costumava ser algo trivial em diversas linguagens de programação. Com o tempo surgiram diversas bibliotecas para facilitar o trabalho com este tipo de arquivo.
A World Wide Web Consortium(http://www.w3.org/) padronizou uma linguagem para leitura de arquivos XML denominada "XML Path Language", ou simplesmente XPath(http://www.w3.org/TR/xpath/). Antes de falar da implementação da XPath em Perl vamos entender alguns conceitos importantes sobre este padrão. Vamos tomar como exemplo o seguinte arquivo XML:

<Biblioteca>
   
<Livro ISBN="1234567" Ano="2000">
        <Paginas>300</Paginas>
        <Titulo>A arte de programar em meia-hora</Titulo>
        <Exemplares>
            <Codigo>1</Codigo>
            <Codigo>2</Codigo>
        </Exemplares>
    </Livro>
    <Livro ISBN="7654321" Ano="1710">
        <Paginas>500</Paginas>
        <Titulo>Aprenda a usar o ábaco em 21 dias</Titulo>
        <Exemplares>
            <Codigo>10</Codigo>
            <Codigo>20</Codigo>
            <Codigo>30</Codigo>
            <Codigo>40</Codigo>
        </Exemplares>
    </Livro>
</Biblioteca>

A XPath prega que um arquivo XML deve ser representado basicamente como uma árvore de Nós, Atributos, Valores e Caminhos.
Nós: As tags do nosso documento. Na figura a seguir podemos ver os nós sendo representados em uma estrutura de árvore:
Atributos: São os atributos internos aos nós. No nó 'Livro', por exemplo, nós temos os atributos 'ISBN' e 'Ano'.
Valores: No contexto de atributo um valor é aquilo que aparece logo depois do sinal de '='. No contexto de nó, um valor é aquele entre a abertura e fechamento de uma tag.
Caminhos: São os "endereços" de cada nó representados na estrutura hierárquica a partir do nó principal. Por exemplo: '//Biblioteca/Livro' representa o endereço do nó Livro no XML. Vejamos outros caminhos possíveis na nossa árvore:


A linguagem XPath determina outra gama de conceitos que não é o foco do nosso post, mas se você se interessar acesse o link http://www.w3.org/TR/xpath/.

A implementação da XPath em Perl está contida no módulo XML::XPath, que você pode instalar diretamente via CPAN ou acessando o link http://search.cpan.org/~msergeant/XML-XPath-1.13/XPath.pm. Para criar um objeto do tipo XML::XPath, fazemos:

my $xpath XML::XPath->new(filename=>$inputFile);

E para procurar por determinado nó, fazemos:

my $nodeset = $xpath->find('//Biblioteca/Livro');

O método find do objeto XML::XPath retornará um conjunto de nós de acordo com o caminho que lhe for passado. No nosso caso será retornado um conjunto de nós 'Livro'. O módulo XML::XPath encapsula o conjunto de nós em um objeto do tipo XML::XPath::NodeSet.
Para iterar no conjunto de nós, o objeto XML::XPath::NodeSet possui o método get_nodelist. Assim, para iterar pelos nós 'Livro' retornados, fazemos:

foreach my $context ($nodeset->get_nodelist) { }

Onde a variável $context a cada iteração estará apontando para o novo 'Livro' pesquisado. Para recuperar os valores dos atributos e nós filhos de cada livro iterado, fazemos:

foreach my $context ($nodeset->get_nodelist) {
    my $isbn = $xpath->findvalue('@ISBN', $context);
    my $ano = $xpath->findvalue('@Ano', $context);
    my $paginas = $xpath->findvalue('Paginas', $context);
    my $titulo = $xpath->findvalue('Titulo', $context);
    my $exemplares = $xpath->find('Exemplares/Codigo', $context);
    foreach my $newcontext ($exemplares->get_nodelist){
        my $codigo = $xpath->findvalue('.', $newcontext);
    }
}

Aqui vale ressaltar que atributos(ISBN e Ano no nosso exemplo) de nós são recuperados somente com o sinal de '@' antes do nome do atributo. Os nós-folhas 'Paginas' e 'Titulo' aparecem somente uma vez em cada livro, logo, podemos pegar o valor diretamente através do método findvalue. No caso dos exemplares, podem existir diversos códigos, por isso tivemos que iterar pelo conjunto de nós retornados através do método find pertencente ao objeto XML::XPath.

A diferença básica do método find e o método findvalue é que o primeiro retorna o conjunto de nós encapsulado em um objeto XML::XPath::NodeSet, o qual poderá ser iterado via método get_nodelist, já o método findvalue retorna o conjunto de nós em uma String encapsulada no objeto XML::XPath::Literal, o qual obviamente não poderá ser iterado.

Aqui vai o exemplo completo de um programa para parsear o arquivo xml mostrado no início do post:

#!/usr/bin/perl

use XML::XPath;
my $inputFile = shift;
die("Faltou passar o nome do arquivo!") unless defined($inputFile);
my $xpath = XML:: XPath->new(filename => $inputFile);
my $nodeset = $xpath->find('//Biblioteca/Livro');
foreach my $context ($nodeset->get_nodelist) {
    print "----------------------------------------------------\n";
    my $isbn = $xpath->findvalue('@ISBN', $context);
    print "ISBN: $isbn\n";
    my $ano = $xpath->findvalue('@Ano', $context);
    print "Ano de Publicação: $ano\n";
    my $paginas = $xpath->findvalue('Paginas', $context);
    print "Quantidade de Páginas: $paginas\n";
    my $titulo = $xpath->findvalue('Titulo', $context);
    print "Título: $titulo\n";
    my $exemplares = $xpath->find('Exemplares/Codigo', $context);
    print "Exemplares disponíveis:\n";
    foreach my $newcontext ($exemplares->get_nodelist){
        my $codigo = $xpath->findvalue('.', $newcontext);
        print "\tCódigo: $codigo\n";
    }
}
print "----------------------------------------------------\n";


O módulo XML::XPath é muito simples de ser utilizado, apesar da complexidade da estrutura interna de objetos que são criados para representar o XML. Esta complexa estrutura torna caro sua utilização, visto que para XML grandes o tempo de processamento e de memória utilizada serão muito grandes.

Existem outros módulos para leitura de XML em Perl que são computacionalmente mais baratos, mas que não implementam o padrão XPath, como o XML::Simple. No próximo post falarei um pouco mais sobre o XML::Simple.

Abraços.

Tá procurando artigos sobre Perl?

Author PerlBrasil Category

No site da comunidade São Paulo Perl Mongers tem uma área de artigos muito rica em diversidade de temas. Lá tem artigos desde introdução à linguagem até técnicas de teste de software utilizando Perl. Vale a pena conferir:

http://sao-paulo.pm.org/artigos

Outra boa fonte de artigos está no site perlmonks.com:

http://www.perlmonks.com/?node=Tutorials

Não podemos esquecer da documentação online do Perl:

http://perldoc.perl.org/index-tutorials.html

Juntando os livros disponibilizados no disco virtual e os artigos postados neste post, vocês tem uma rica base de informação para usufruir. Então não percam tempo e comecem a conhecer esta poderosa linguagem. Qualquer dúvida podem nos enviar email ou utilizar a página de contato do blog.

Novos Livros no Disco Virtual

Author PerlBrasil Category

O disco virtual do blog foi atualizado com diversos livros, tais como, Beginning Perl, Modern Perl, Extreme Perl, Impatient Perl entre outros. Vale lembrar que todos estes livros permitem distribuição livre, ou seja, não precisam me denunciar por infringir leis de direitos autorais ;)

Aconselho veemente começar pelo Beginning Perl, que é um excelente livro.

Abraços e boa leitura.

Equinócio de Março

Author PerlBrasil Category

A comunidade Perl Mongers de São Paulo - http://sao-paulo.pm.org - está comemorando neste mês o equinócio de Março, trazendo artigos sobre a linguagem Perl com foco no projeto OpenData-Br. O calendário do Equinócio pode ser acompanhado no link http://sao-paulo.pm.org/equinocio/2011.

Alpha

Author PerlBrasil Category

Muitas pessoas ao criar um blog não tem bem definido o escopo do conteúdo a ser disponibilizado. Não é o nosso caso. O PerlBrasil surge para suprir a lacuna de blogs em língua portuguesa sobre a linguagem de programação Perl.
Traremos tutoriais, artigos, dicas e notícias, sempre contando com a ajuda de vocês leitores. Lembrem-se que este blog não é um canal unidirecional, nós mostraremos o conteúdo e vocês postarão as dúvidas, críticas e sugestões para construírmos juntos um espaço cada vez melhor.
Grande abraço a todos.

Theme by New wp themes | Bloggerized by Dhampire