Ruby - Tutorial XML, XSLT e XPath

Cos'è l'XML?

L'Extensible Markup Language (XML) è un linguaggio di markup molto simile a HTML o SGML. Questo è consigliato dal World Wide Web Consortium e disponibile come standard aperto.

XML è un linguaggio portatile e open source che consente ai programmatori di sviluppare applicazioni che possono essere lette da altre applicazioni, indipendentemente dal sistema operativo e / o dal linguaggio di sviluppo.

XML è estremamente utile per tenere traccia di piccole e medie quantità di dati senza richiedere un backbone basato su SQL.

API e architetture di parser XML

Sono disponibili due diversi gusti per i parser XML:

  • SAX-like (Stream interfaces)- Qui si registrano i callback per gli eventi di interesse e quindi si lascia che il parser proceda attraverso il documento. Questo è utile quando i tuoi documenti sono grandi o hai limitazioni di memoria, analizza il file mentre lo legge dal disco e l'intero file non viene mai archiviato in memoria.

  • DOM-like (Object tree interfaces) - Questa è la raccomandazione del World Wide Web Consortium in cui l'intero file viene letto in memoria e archiviato in una forma gerarchica (basata su albero) per rappresentare tutte le caratteristiche di un documento XML.

Ovviamente SAX non può elaborare le informazioni alla velocità di DOM quando si lavora con file di grandi dimensioni. D'altra parte, l'uso esclusivo di DOM può davvero uccidere le tue risorse, specialmente se usato su molti piccoli file.

SAX è di sola lettura, mentre DOM consente modifiche al file XML. Poiché queste due API diverse si completano letteralmente a vicenda, non c'è motivo per cui non puoi usarle entrambe per progetti di grandi dimensioni.

Analisi e creazione di XML utilizzando Ruby

Il modo più comune per manipolare XML è con la libreria REXML di Sean Russell. Dal 2002, REXML fa parte della distribuzione standard di Ruby.

REXML è un processore XML puro Ruby conforme allo standard XML 1.0. È un processore non convalidante , che supera tutti i test di conformità non convalidanti OASIS.

Il parser REXML presenta i seguenti vantaggi rispetto ad altri parser disponibili:

  • È scritto al 100 percento in Ruby.
  • Può essere utilizzato sia per l'analisi SAX che per quella DOM.
  • È leggero, meno di 2000 righe di codice.
  • I metodi e le classi sono davvero facili da capire.
  • API basata su SAX2 e supporto completo di XPath.
  • Viene fornito con l'installazione di Ruby e non è richiesta alcuna installazione separata.

Per tutti i nostri esempi di codice XML, utilizziamo un semplice file XML come input -

<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>

Analisi simile a DOM

Analizziamo prima i nostri dati XML in modo albero . Iniziamo richiedendo il filerexml/documentbiblioteca; spesso includiamo REXML da importare nello spazio dei nomi di primo livello per comodità.

#!/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 
}

Questo produrrà il seguente risultato:

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

Analisi simile a SAX

Per elaborare gli stessi dati, movies.xml , file in modo orientato al flusso , definiremo una classe listener i cui metodi saranno l'obiettivo dei callback dal parser.

NOTE - Non è consigliabile utilizzare l'analisi simile a SAX per un piccolo file, questo è solo per un esempio demo.

#!/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)

Questo produrrà il seguente risultato:

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

Un modo alternativo per visualizzare XML è XPath. Si tratta di una specie di pseudo-linguaggio che descrive come individuare elementi e attributi specifici in un documento XML, trattando quel documento come un albero logico ordinato.

REXML ha il supporto XPath tramite la classe XPath . Presuppone l'analisi basata sugli alberi (modello a oggetti del documento) come visto sopra.

#!/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

Questo produrrà il seguente risultato:

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

XSLT e Ruby

Sono disponibili due parser XSLT che Ruby può usare. Di seguito viene fornita una breve descrizione di ciascuno.

Ruby-Sablotron

Questo parser è scritto e mantenuto da Masayoshi Takahashi. È scritto principalmente per il sistema operativo Linux e richiede le seguenti librerie:

  • Sablot
  • Iconv
  • Expat

Puoi trovare questo modulo su Ruby-Sablotron.

XSLT4R

XSLT4R è scritto da Michael Neumann e può essere trovato presso RAA nella sezione Library sotto XML. XSLT4R utilizza una semplice interfaccia a riga di comando, sebbene possa in alternativa essere utilizzata all'interno di un'applicazione di terze parti per trasformare un documento XML.

XSLT4R richiede XMLScan per funzionare, che è incluso nell'archivio XSLT4R e che è anche un modulo Ruby al 100%. Questi moduli possono essere installati utilizzando il metodo di installazione standard di Ruby (ad esempio, ruby ​​install.rb).

XSLT4R ha la seguente sintassi:

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

Se desideri utilizzare XSLT4R da un'applicazione, puoi includere XSLT e inserire i parametri di cui hai bisogno. Ecco l'esempio:

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 )

Ulteriori letture