Ruby-XML、XSLT、XPathチュートリアル

XMLとは何ですか?

Extensible Markup Language(XML)は、HTMLやSGMLによく似たマークアップ言語です。これは、World Wide Web Consortiumによって推奨されており、オープンスタンダードとして利用できます。

XMLは、オペレーティングシステムや開発言語に関係なく、プログラマーが他のアプリケーションで読み取ることができるアプリケーションを開発できるようにする、移植可能なオープンソース言語です。

XMLは、SQLベースのバックボーンを必要とせずに、少量から中量のデータを追跡するのに非常に役立ちます。

XMLパーサーのアーキテクチャとAPI

XMLパーサーで使用できる2つの異なるフレーバーがあります-

  • SAX-like (Stream interfaces)−ここでは、関心のあるイベントのコールバックを登録してから、パーサーにドキュメントを進めさせます。これは、ドキュメントが大きい場合やメモリに制限がある場合に便利です。ディスクからファイルを読み取るときにファイルを解析し、ファイル全体がメモリに保存されることはありません。

  • DOM-like (Object tree interfaces) −これはWorld Wide Web Consortiumの推奨事項であり、ファイル全体がメモリに読み込まれ、階層(ツリーベース)形式で格納されて、XMLドキュメントのすべての機能を表します。

SAXは、大きなファイルを処理する場合、DOMほど高速に情報を処理できないことは明らかです。一方、DOMを排他的に使用すると、特に多くの小さなファイルで使用する場合、リソースが実際に停止する可能性があります。

SAXは読み取り専用ですが、DOMではXMLファイルへの変更が許可されています。これらの2つの異なるAPIは文字通り互いに補完し合うため、大規模なプロジェクトで両方を使用できない理由はありません。

Rubyを使用したXMLの解析と作成

XMLを操作する最も一般的な方法は、SeanRussellによるREXMLライブラリを使用することです。2002年以来、REXMLは標準のRubyディストリビューションの一部となっています。

REXMLは、XML1.0標準に準拠した純粋なRubyXMLプロセッサです。これは非検証プロセッサであり、すべてのOASIS非検証適合性テストに合格しています。

REXMLパーサーには、他の利用可能なパーサーに比べて次の利点があります。

  • それはRubyで100パーセント書かれています。
  • SAXとDOMの両方の解析に使用できます。
  • 軽量で、2000行未満のコードです。
  • メソッドとクラスは本当に理解しやすいです。
  • SAX2ベースのAPIと完全なXPathサポート。
  • Rubyインストールで出荷され、個別のインストールは必要ありません。

すべてのXMLコード例について、単純なXMLファイルを入力として使用しましょう-

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

DOMのような構文解析

まず、XMLデータをツリー形式で解析しましょう。まず、rexml/document図書館; 多くの場合、便宜上、インクルードREXMLを実行してトップレベルの名前空間にインポートします。

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

これにより、次の結果が生成されます-

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

SAXのような構文解析

同じデータ、movies.xml、ファイルをストリーム指向の方法で処理するために、パーサーからのコールバックのターゲットとなるメソッドを持つリスナークラスを定義します。

NOTE −小さなファイルにSAXのような解析を使用することはお勧めしません。これは、デモの例にすぎません。

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

これにより、次の結果が生成されます-

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

XMLを表示する別の方法はXPathです。これは、XMLドキュメント内の特定の要素と属性を検索し、そのドキュメントを論理的に順序付けられたツリーとして扱う方法を説明する一種の疑似言語です。

REXMLは、XPathクラスを介してXPathをサポートしています。上で見たように、ツリーベースの解析(ドキュメントオブジェクトモデル)を想定しています。

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

これにより、次の結果が生成されます-

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

XSLTとRuby

Rubyで使用できるXSLTパーサーは2つあります。それぞれの簡単な説明をここに示します。

ルビー-サブロトロン

このパーサーは、高橋正義によって作成および保守されています。これは主にLinuxOS用に書かれており、次のライブラリが必要です-

  • Sablot
  • Iconv
  • Expat

このモジュールは次の場所にあります。 Ruby-Sablotron

XSLT4R

XSLT4RはMichaelNeumannによって作成され、XMLの下のライブラリセクションのRAAにあります。XSLT4Rは単純なコマンドラインインターフェイスを使用しますが、代わりにサードパーティアプリケーション内で使用してXMLドキュメントを変換することもできます。

XSLT4Rが動作するには、XMLScanが必要です。XMLScanはXSLT4Rアーカイブに含まれており、100%Rubyモジュールでもあります。これらのモジュールは、標準のRubyインストール方法(つまり、ruby install.rb)を使用してインストールできます。

XSLT4Rの構文は次のとおりです-

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

アプリケーション内からXSLT4Rを使用する場合は、XSLTを含めて、必要なパラメーターを入力できます。これが例です-

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 )

参考文献

  • REXMLパーサーの詳細については、REXMLパーサーのドキュメントの標準ドキュメントを参照してください。

  • XSLT4RはRAAリポジトリからダウンロードできます。