XML em Perl, parte 2

Continuando o assunto da semana passada e relembrando que o módulo do XML-Simple foi instalado e esteja funcionando corretamente. Agora é a vez de explicar como ele funciona e como é utilizado e,  como já dito: “começando do princípio que é para não ter gente perdida no meio do caminho”.

Atenção : Se você sabe o que são scalar, array e hash, pode pular a primeira parte e ir direto para a seguinte.

Variáveis em Perl

Antes de prosseguir é bom explicar uma coisa, ou melhor, três. Em Perl as variáveis são chamadas de escalares (“scalar“) e são precedidas por um sinal de cifrão (“$”):

$a=1;
$b='a';

Quando se agrupa um conjunto de escalares temos um vetor (“array“) e o identificamos com um sinal de arroba (“@”):

@a=(1,2,3);
@b=('a','b','c');

Deve-se usar o arroba sempre que o array for tratado como um todo (conjunto), mas para fazer referência a um item específico (elemento) usa-se o cifrão junto da referência da sua posição dentro do vetor entre colchetes (“[…]”) — o primeiro item é sempre zero e não um:

print $a[0]." e ".$b[0]."\n";
2 e b

Uma outra estrutura de dados é o vetor associativo (“hash“), você o identifica com um sinal de porcentagem (“%”) e sua diferença com o array está justamente no fato dele não ser acessado pelo seu número de ordem (0, 1, 2 …) mas sim por uma chave (“key“), ou seja:

%tudo=( a=>1, b=>2, c=>3 );

Na realidade a ordem dos elementos não faz o menor sentido dentro do vetor associativo. Como acontece no array você faz referência ao conjunto usando porcentagem e aos elementos usando o cifrão com a key entre chaves (“{…}”):

print $tudo{b}."\n";
2

Agora, justamente para confundir um pouco, vou dizer que você não precisa usar a porcentagem para criar um hash! Basta fazer assim:

$tudo={ a=>1, b=>2, c=>3 }

Este sujeito é chamado de hash anônimo, e a forma como você tratará os elementos sofre uma pequena alteração na grafia (é a magia do Perl se manifestando):

print $tudo->{b}."\n";
b

Imagine o hash como um tipo de banco de dados armazenado na memória, mais precisamente um banco em árvore já que é possível aninhar um hash dentro de outro hash e dentro de outro… — ou mesmo dentro de um array mas daí as coisas vão ficando mais complexas.

Se quiser saber um pouco mais sobre o assunto consulte o Perl Hash Howto ou o tópico sobre o assunto no Perl 101.

Como o XML::Simple funciona

Agora sim, posso contar sem gerar celeuma que aquilo que o XML::Simple faz é ler o arquivo XML, analisá-lo (parsing) e transformá-lo em um hash através da função XMLin(). E também o caminho contrário, formatando um hash específico como se fosse um arquivo XML com a função XMLout(). Creio que agora também ficou claro a razão do simples do nome dele.

Um pedido, será necessário instalar o módulo Data::Dumper (creio que depois de toda aquela encheção de saco sobre a instalação do XML::Simple você saiba como fazê-lo). Ele não tem relação alguma com XML mas será útil para enxergar dentro das variáveis e visualizar a estrutura do seu conteúdo.

Lendo um arquivo XML

Relembrando o código que foi usado para testar o módulo, o agenda1.pl:

#!/usr/bin/perl
use XML::Simple;
my $xml=new XML::Simple;
my $data=$xml->XMLin("agenda.xml");
print $data->{entry}{Fulano}{phone}."\n";
exit 0;

O comando ‘use’ diz para o Perl para adicionar (usar) o módulo XML::Simple. A variável $xml é o objeto criado (new) com a classe XML::Simple. E, finalmente, usamos a função (ou o método) XMLin() do objeto $xml passando como parâmetro o nome do arquivo XML que será lido.

É claro que não custa lembrar que, ao contrário do comando ‘use’ em que o Perl sabe exatamente por onde procurar os módulos,  você precisará explicitar a localização do arquivo XML, senão receberá algo assim:

File does not exist: agenda.xml at ./agenda1.pl line 4.

Agora uma pequena adaptação no programa, salvem a nova versão como agenda2.pl para não perder o primeiro exemplo:

#!/usr/bin/perl
use XML::Simple;
use Data::Dumper;
my $xml = new XML::Simple;
my $data = $xml->XMLin("agenda.xml");
print Dumper($data);
exit 0;

E ao executá-lo o resultado será mais ou menos assim:

$VAR1 = {
          'entry' => {
                     'Fulano' => {
                                 'phone' => '1234-5678',
                               },
                     'Sicrano' => {
                                  'phone' => '8765-4321'
                                }
                   }
        };

Se tentássemos exibir o conteúdo de um hash (ou um array) apenas co o comando “print” o resultado seria algo como “HASH({endereço da memória})”. O que o Data::Dumper faz é exibir o que existe dentro de uma variável na forma como está estruturado — o PHP tem uma função parecida, a print_r() — e é muito útil quando não se sabe a estrutura do que está dentro da variável (o que é nosso caso).

Assim ficou fácil perceber que o o XML foi convertido em um hash — porque key e colchetes — com um elemento identificado como ‘entry’ (pois é, é conversão automática de dados, nunca espere milagres!) e dentro de cada elemento há um hash com dois elementos de índices ‘Fulano’ e ‘Sicrano’, respectivamente Cada um contendo um outro hash de índice ‘phone’ cujo valor é o número de telefone de cada um.

É agora que o $data->{entry}{Fulano}{phone} do programa de exemplo passa a fazer algum sentido. Obviamente que o XML de referência é tão simplório que chega a dar dó, então é hora de sofisticá-lo:

<?xml version='1.0'?>
<agenda>
 <entry>
  <name>Fulano</name>
   <full>Fulano da Silva</full>
   <prefix>Sr.</prefix>
   <email>fulano@example.com</email>
   <phone>1234-5678</phone>
   <phone>1234-8765</phone>
   <address>Avenida Projetada, 700 sala A</address>
  </entry>
  <entry>
   <name>Sicrano</name>
   <full>Sicrano de Souza</full>
   <prefix>Dr.</prefix>
   <email>doutorsicrano@example.com</email>
   <address>Travessa A, 123</address>
   <phone>8765-4321</phone>
  </entry>
</agenda>

Rode várias vezes este programa para reparar que em cada execução a ordem no hash resultante é diferente da que foi exibida antes — lembra de eu ter dito que não há ordenação em hashes?). Ao rodar novamente o programa é possível ver algo com uma cara mais de banco de dados, cada entrada para ‘Fulano’ e ‘Sicrano’ possuindo um conjunto mais substancial de informações atreladas ao seu hash. Viu o que aconteceu com o telefone do ‘Fulano’? Execute o agenda1.pl só para ver que o resultado agora será algo mais ou menos assim:

$ ./agenda1.pl 
ARRAY(0x22c7570)

Para consertar o agenda1.pl faça assim e o chame de agenda3.pl:

#!/usr/bin/perl
use XML::Simple;
my $xml = new XML::Simple;
my $data = $xml->XMLin("agenda.xml");
my $j=$data->{entry}{Fulano}{phone};
if ( ref( $j ) eq 'ARRAY')
{
    foreach my $i ( @{$j} )
    {
        print $i."\n";
    }
}
else
{
    print $j."\n";
}
exit 0;

Ou seja, verifica-se qual o tipo de dados está armazenado dentro da (se é escalar ou vetor) e usa-se uma rotina diferente de impressão para cada uma delas. A parte curiosa do código é o @{…} força a interpretação da variável como um vetor e assim o foreach sabe o que fazer com ela.

E por enquanto chega, na próxima parte será o momento de acrescentar coisas ao XML.

Anúncios

Um comentário sobre “XML em Perl, parte 2

  1. Pingback: XML em Perl, parte 3 | giovannireisnunes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s