Ruby tem hoje uma das bibliotecas mais impressionantes e fáceis para se manipular informações em formato XML. A biblioteca REXML (Ruby Electric XML).

Essa biblioteca é baseada na biblioteca Electric XML para Java, porém em Ruby é bem mais fácil de se usar tal biblioteca. Aliás, você não fica restrito apenas a manipulação de XML com o REXML, você também poderá usá-la para manipulação de informações no formato XHTML. Como o XHTML tem padrões rigorosos definidos, podemos usar o REXML tranqüilamente. Mas se você precisa manipular HTML, use o hpricot.

Nesse post, eu mostro o básico de uma leitura XML usando a REXML. Em nosso exemplo utilizaremos o webservice de pesquisa do Yahoo. Basicamente iremos ler o XML que o Yahoo nos fornece e iremos exibi-los em console.

Primeiro de tudo vamos ver qual a estrutura do XML que o Yahoo nos fornece para fazermos a leitura. A URL do XML é essa: http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=metallica&results=5

Repare na URL que eu passei acima as variáveis que passei via GET. Uma é a palavra chave de busca (query) e a outra o número de resultados que eu quero por página (results). Estão com os valores “metallica” e “5” respectivamente. Se quiser se aprofundar na API de busca do Yahoo, consulte o site do developers do Yahoo.

Voltando a XML fornecida pelo Yahoo, vamos analisa-la:

Estrutura básica do XML do Yahoo

Cada “caixa” em azul representa um nó no XML. Tudo começa com um nó raiz (ResultSet) e depois desce para o nó de resultado (Result). Esse nós repsenta um item do resultado da pesquisa feita no Yahoo. Se houve mais resultados, então o nó Result é repetido.

Em nosso tutorial, vamos ler as informações que estão nos nós “Title”, “Summary”, “Url” e “MimeType” que não se encontra no mapeamento acima porque não houve espaço para colocar todos os nós. De uma olhada no documento do Yahoo que você irá ver lá.

Agora que sabemos as informações que iremos ler, vamos começar a codificar.

Vamos criar uma classe “Buscador” que irá se conectar ao webservice do Yahoo, ler toda a XML e inicializar nossos atributos de instância no construtor. Depois criaremos um método que irá ler os nós  específicos do XML que queremos.

Comecemos pelos imports das bibliotecas e pelo construtor:

# Leitura de XML usando a biblioteca REXML
# do Ruby. Em nosso exemplo usaremos o
# webservice de busca do Yahoo.
 
class Buscador
 
   # Import dos GEMs usados e do REXML
   require 'rubygems'
   require 'open-uri'
   require 'rexml/document'
 
   #Vamos inicializar as variáveis para a busca e instanciar
   #nosso objeto REXML que será usado para a busca no Yahoo.
   def initialize(keywords, resultado_pagina)
      @keywords = keywords
      @resultado_pagina = resultado_pagina
      @url_yahoo = "http://api.search.yahoo.com/WebSearchService/V1/
webSearch?appid=YahooDemo&query=#{@keywords}&results=#{@resultado_pagina}"
 
      # Aqui você pode usar o open do gem open-uri ou
      # a classe net/http. O open é bem mais simples :).
      xml_data = open(@url_yahoo)
      @obj_rexml = REXML::Document.new(xml_data.read)
   end
end

Repare no código acima que nosso construtor recebe dois parâmetros. O keywords são as palavras chave que usaremos na busca e o resultado_pagina é o número de resultados que queremos que sejam exibidos no XML. Esse parâmetros são aqueles já explicados acima nesse mesmo post.

Outro detalhe no código é o uso do open. Nele, passamos somente a URL que queremos ler e ele nos retorna os dados com o método read. Incrível. Cada vez mais eu gosto de Ruby!

Logo abaixo do open, está a instanciação do objeto REXML, o qual usaremos para ler o XML no método que criaremos.

Criado o construtor, vamos criar nosso pequeno método que faz a leitura do XML e nos retorna o resultado.

A cada resultado que o Yahoo nos retornar, iremos criar um hash para esse resultado. Preenchido o hash com as informações do XML colocaremos esse hash dentro de um array. Faremos isso até finalizar a leitura do XML. Terminada a leitura, retornaremos o array. Nossos resultados estarão bem estruturados dentro do array.

Vamos ao método da busca:

   # Esse método realiza a leitura do xml e retorna um array de hash
   # com o resultado da leitura.
   def buscar
      lista_resultado = Array.new #array com todos os resultados
 
      # Caminho dos nos no XML. Dependendo do que você quiser
      # no XML, vai ser aqui você irá muda.
      nos = "ResultSet/Result"
 
      # Loop entre os nos do XML definido acima
      @obj_rexml.elements.each(nos) do |elemento|
         resultado = Hash.new #hash que vai conter um resultado
 
         resultado[:titulo] = elemento.text("Title")
         resultado[:descricao] = elemento.text("Summary")
         resultado[:link] = elemento.text("Url")
         resultado[:tipo] = elemento.text("MimeType")
 
         # Guarda o hash no array e continua o loop
         lista_resultado < < resultado
      end
 
      # Retorna o Array com os resultados
      return lista_resultado
   end

Explicando o que se passa nesse método:

  • lista_resultado: Nosso array onde ficarão os hash de cada resultado individual.
  • nos: é o “caminho” no XML que queremos. Tudo o que estiver dentro desse caminho, ele irá nos retornar.
  • @obj_rexml.elements.each(nos) do |elemento|: Loop entre os nós dentro do caminho passado.
  • resultado: Hash que representa um resultado individual.
  • resultado[:titulo] = elemento.text(“Title”): Inserção no Hash (posição :title) o elemento XML que contém um nó chamado “Title”.
  • lista_resultado << resultado: Insere o hash no array
  • return lista_resultado: Retorna o array com os resultados!

O método .text(nó) chamado pelo objeto elemento significa que queremos o texto que está dentro do nó passado como parâmetro. Quando há um atributo no nó, podemos utilizar o método .attributte(atributo). Por exemplo, supondo que um nó possua um atributo “id=5” da seguinte forma: <title id=”5”>Texto do Título</title>. Então poderíamos utilizar o método assim:

elemento.attributte(“id”)
=> 5

Bem legal!

Pronto! Muito simples. Nossa classe está pronta. No final das contas teremos o seguinte código:

class Buscador
 
   require 'rubygems'
   require 'open-uri'
   require 'rexml/document'
 
   def initialize(keywords, resultado_pagina)
      @keywords = keywords
      @resultado_pagina = resultado_pagina
      @url_yahoo = "http://api.search.yahoo.com/WebSearchService/V1/
webSearch?appid=YahooDemo&amp;query=#{@keywords}&amp;results=#{@resultado_pagina}"
 
      xml_data = open(@url_yahoo)
      @obj_rexml = REXML::Document.new(xml_data.read)
   end
 
   def buscar
      lista_resultado = Array.new #array com todos os resultados
 
      nos = "ResultSet/Result"
 
      @obj_rexml.elements.each(nos) do |elemento|
         resultado = Hash.new #hash que vai conter um resultado
 
         resultado[:titulo] = elemento.text("Title")
         resultado[:descricao] = elemento.text("Summary")
         resultado[:link] = elemento.text("Url")
         resultado[:tipo] = elemento.text("MimeType")
 
         lista_resultado < < resultado
      end
 
      return lista_resultado
   end
 
end

Para testarmos a classe recém-criada, você pode implementar o seguinte script logo após o fechamento da classe:

# Configurações do script
# As configurações abaixo são configurações básicas para uso no
# webservie do Yahoo.
keywords = "metallica+one"
resultados_por_pagina = 10
 
busca = Buscador.new(keywords, resultados_por_pagina)
resultados = busca.buscar
 
resultados.each do |item_achado|
   puts "Titulo: #{item_achado[:titulo]}"
   puts "Descricao: #{item_achado[:descricao]}"
   puts "Link: #{item_achado[:link]}"
   puts "Tipo: #{item_achado[:tipo]}"
   puts "-------------------------------------"
end

Executando o nosso exemplo teremos os seguintes exemplos de resultados:

Titulo: One (Metallica song) - Wikipedia, the free encyclopedia
Descricao: Metallica won their first Grammy Award in 1990 for "One", winning Best Metal ... "One" was written in November 1987 by Metallica's principal composers — rhythm ...
Link: http://en.wikipedia.org/wiki/One_(Metallica_song)
Tipo: text/html
-------------------------------------
Titulo: YouTube - Metallica - One
Descricao: Video of One by MetallicAMovie: Johnny Got His Gun ... one of the best songs by MetallicA. kingxwrong (2 hours ago) Show Hide +1. Marked as spam ...
Link: http://www.youtube.com/watch?v=-j39ABZyzek
Tipo: text/html
-------------------------------------
Titulo: YouTube - Metallica- One
Descricao: Metallica's music video "One" ... One - Metallica (Live 1989) 07:00 From: metallicafx. Views: 2,551,898. Loading...
Link: http://www.youtube.com/watch?v=JwW9L_qzqp8
Tipo: text/html

Com esse simples (bem simples mesmo) exemplo que criamos, mostramos a força do REXML. Usando o próprio Yahoo, podemos criar nosso próprio search engine com o Rails baseado no motor de busca do Yahoo. Por que não? Afinal as possibilidade são infinitas.

Se quiser se aprender mais sobre a manipulação de REXML segue alguns links:

É isso pessoal. Espero que tenham gostado do REXML assim como eu e até o próximo post!

  • Share/Bookmark