Ruby - Tutorial de XML, XSLT e XPath

O que é XML?

A Extensible Markup Language (XML) é uma linguagem de marcação muito parecida com HTML ou SGML. Isso é recomendado pelo World Wide Web Consortium e está disponível como um padrão aberto.

XML é uma linguagem portátil e de código aberto que permite aos programadores desenvolver aplicativos que podem ser lidos por outros aplicativos, independentemente do sistema operacional e / ou linguagem de desenvolvimento.

XML é extremamente útil para rastrear pequenas e médias quantidades de dados sem exigir um backbone baseado em SQL.

Arquiteturas XML Parser e APIs

Existem dois sabores diferentes disponíveis para analisadores XML -

  • SAX-like (Stream interfaces)- Aqui você registra retornos de chamada para eventos de interesse e, em seguida, permite que o analisador prossiga pelo documento. Isso é útil quando seus documentos são grandes ou você tem limitações de memória, ele analisa o arquivo à medida que o lê do disco e o arquivo inteiro nunca é armazenado na memória.

  • DOM-like (Object tree interfaces) - Esta é a recomendação do World Wide Web Consortium em que todo o arquivo é lido na memória e armazenado em uma forma hierárquica (baseada em árvore) para representar todos os recursos de um documento XML.

Obviamente, o SAX não pode processar informações tão rápido quanto o DOM ao trabalhar com arquivos grandes. Por outro lado, usar o DOM exclusivamente pode realmente matar seus recursos, especialmente se usado em muitos arquivos pequenos.

SAX é somente leitura, enquanto DOM permite alterações no arquivo XML. Uma vez que essas duas APIs diferentes se complementam literalmente, não há razão para que você não possa usá-las para grandes projetos.

Análise e criação de XML usando Ruby

A maneira mais comum de manipular XML é com a biblioteca REXML de Sean Russell. Desde 2002, REXML faz parte da distribuição padrão do Ruby.

REXML é um processador XML Ruby puro em conformidade com o padrão XML 1.0. É um processador de não validação , passando em todos os testes de conformidade de não validação OASIS.

O analisador REXML tem as seguintes vantagens sobre outros analisadores disponíveis -

  • Está escrito 100 por cento em Ruby.
  • Ele pode ser usado para análise SAX e DOM.
  • É leve, com menos de 2.000 linhas de código.
  • Métodos e classes são realmente fáceis de entender.
  • API baseada em SAX2 e suporte completo a XPath.
  • Enviado com a instalação do Ruby e nenhuma instalação separada é necessária.

Para todos os nossos exemplos de código XML, vamos usar um arquivo XML simples como entrada -

<collection shelf = "New Arrivals">
   <movie title = "Enemy Behind">
      <type>War, Thriller</type>
      <format>DVD</format>
      <year>2003</year>
      <rating>PG</rating>
      <stars>10</stars>
      <description>Talk about a US-Japan war</description>
   </movie>
   <movie title = "Transformers">
      <type>Anime, Science Fiction</type>
      <format>DVD</format>
      <year>1989</year>
      <rating>R</rating>
      <stars>8</stars>
      <description>A schientific fiction</description>
   </movie>
   <movie title = "Trigun">
      <type>Anime, Action</type>
      <format>DVD</format>
      <episodes>4</episodes>
      <rating>PG</rating>
      <stars>10</stars>
      <description>Vash the Stampede!</description>
   </movie>
   <movie title = "Ishtar">
      <type>Comedy</type>
      <format>VHS</format>
      <rating>PG</rating>
      <stars>2</stars>
      <description>Viewable boredom</description>
   </movie>
</collection>

Análise semelhante a DOM

Vamos primeiro analisar nossos dados XML em forma de árvore . Começamos exigindo orexml/documentbiblioteca; frequentemente, incluímos REXML para importar para o namespace de nível superior por conveniência.

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML

xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)

# Now get the root element
root = xmldoc.root
puts "Root element : " + root.attributes["shelf"]

# This will output all the movie titles.
xmldoc.elements.each("collection/movie"){ 
   |e| puts "Movie Title : " + e.attributes["title"] 
}

# This will output all the movie types.
xmldoc.elements.each("collection/movie/type") {
   |e| puts "Movie Type : " + e.text 
}

# This will output all the movie description.
xmldoc.elements.each("collection/movie/description") {
   |e| puts "Movie Description : " + e.text 
}

Isso produzirá o seguinte resultado -

Root element : New Arrivals
Movie Title : Enemy Behind
Movie Title : Transformers
Movie Title : Trigun
Movie Title : Ishtar
Movie Type : War, Thriller
Movie Type : Anime, Science Fiction
Movie Type : Anime, Action
Movie Type : Comedy
Movie Description : Talk about a US-Japan war
Movie Description : A schientific fiction
Movie Description : Vash the Stampede!
Movie Description : Viewable boredom

Análise semelhante a SAX

Para processar os mesmos dados, movies.xml , arquivo de uma maneira orientada a fluxo , definiremos uma classe de ouvinte cujos métodos serão o alvo de callbacks do analisador.

NOTE - Não é sugerido usar análise semelhante a SAX para um arquivo pequeno, isso é apenas para um exemplo de demonstração.

#!/usr/bin/ruby -w

require 'rexml/document'
require 'rexml/streamlistener'
include REXML

class MyListener
   include REXML::StreamListener
   def tag_start(*args)
      puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}"
   end

   def text(data)
      return if data =~ /^\w*$/     # whitespace only
      abbrev = data[0..40] + (data.length > 40 ? "..." : "")
      puts "  text   :   #{abbrev.inspect}"
   end
end

list = MyListener.new
xmlfile = File.new("movies.xml")
Document.parse_stream(xmlfile, list)

Isso produzirá o seguinte resultado -

tag_start: "collection", {"shelf"=>"New Arrivals"}
tag_start: "movie", {"title"=>"Enemy Behind"}
tag_start: "type", {}
   text   :   "War, Thriller"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Talk about a US-Japan war"
tag_start: "movie", {"title"=>"Transformers"}
tag_start: "type", {}
   text   :   "Anime, Science Fiction"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "A schientific fiction"
tag_start: "movie", {"title"=>"Trigun"}
tag_start: "type", {}
   text   :   "Anime, Action"
tag_start: "format", {}
tag_start: "episodes", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Vash the Stampede!"
tag_start: "movie", {"title"=>"Ishtar"}
tag_start: "type", {}
tag_start: "format", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
   text   :   "Viewable boredom"

XPath e Ruby

Uma forma alternativa de visualizar XML é XPath. Este é um tipo de pseudo-linguagem que descreve como localizar elementos e atributos específicos em um documento XML, tratando esse documento como uma árvore ordenada lógica.

REXML tem suporte XPath por meio da classe XPath . Ele assume a análise baseada em árvore (modelo de objeto de documento) como vimos acima.

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML

xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)

# Info for the first movie found
movie = XPath.first(xmldoc, "//movie")
p movie

# Print out all the movie types
XPath.each(xmldoc, "//type") { |e| puts e.text }

# Get an array of all of the movie formats.
names = XPath.match(xmldoc, "//format").map {|x| x.text }
p names

Isso produzirá o seguinte resultado -

<movie title = 'Enemy Behind'> ... </>
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]

XSLT e Ruby

Existem dois analisadores XSLT disponíveis que Ruby pode usar. Uma breve descrição de cada um é fornecida aqui.

Ruby-Sablotron

Este analisador foi escrito e mantido por Masayoshi Takahashi. Isso foi escrito principalmente para o sistema operacional Linux e requer as seguintes bibliotecas -

  • Sablot
  • Iconv
  • Expat

Você pode encontrar este módulo em Ruby-Sablotron.

XSLT4R

XSLT4R foi escrito por Michael Neumann e pode ser encontrado no RAA na seção Biblioteca em XML. O XSLT4R usa uma interface de linha de comando simples, embora possa, alternativamente, ser usado em um aplicativo de terceiros para transformar um documento XML.

O XSLT4R precisa do XMLScan para operar, que está incluído no arquivo XSLT4R e que também é um módulo Ruby 100 por cento. Esses módulos podem ser instalados usando o método de instalação padrão do Ruby (ou seja, ruby ​​install.rb).

XSLT4R tem a seguinte sintaxe -

ruby xslt.rb stylesheet.xsl document.xml [arguments]

Se quiser usar o XSLT4R de dentro de um aplicativo, você pode incluir o XSLT e inserir os parâmetros necessários. Aqui está o exemplo -

require "xslt"

stylesheet = File.readlines("stylesheet.xsl").to_s
xml_doc = File.readlines("document.xml").to_s
arguments = { 'image_dir' => '/....' }
sheet = XSLT::Stylesheet.new( stylesheet, arguments )

# output to StdOut
sheet.apply( xml_doc )

# output to 'str'
str = ""
sheet.output = [ str ]
sheet.apply( xml_doc )

Leitura Adicional