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


XML とは?

XML は拡張可能マークアップ言語(eXtensible Markup Language)を指します。

拡張可能マークアップ言語は、標準汎用マークアップ言語のサブセットであり、電子ファイルをマークして構造を持たせるためのマークアップ言語です。

これはデータのマーク付けやデータ型の定義に使用でき、ユーザーが自身のマークアップ言語を定義できるようにするソース言語です。ワールドワイドウェブでの転送に非常に適しており、アプリケーションやベンダーに依存しない構造化データを記述および交換するための統一された方法を提供します。

詳細は当サイトのXML チュートリアル


XML パーサーの構造と API

XML のパーサーには主に DOM と SAX の 2 種類があります。

  • SAX パーサーはイベント処理に基づいており、XML 文書を最初から最後までスキャンする必要があります。スキャン中に構文構造に遭遇するたびに、その特定の構文構造のイベントハンドラーが呼び出され、アプリケーションにイベントが送信されます。
  • DOM はドキュメントオブジェクトモデル解析であり、文書の階層的な構文構造を構築し、メモリ内に DOM ツリーを作成します。DOM ツリーのノードはオブジェクトとして識別されます。文書解析が完了すると、文書の DOM ツリー全体がメモリ内に配置されます。

Ruby での XML の解析と作成

Ruby で XML 文書を解析するには、この REXML ライブラリを使用できます。

REXML ライブラリは Ruby の XML ツールキットであり、純粋な Ruby 言語で記述され、XML 1.0 仕様に準拠しています。

Ruby 1.8 以降では、Ruby 標準ライブラリに REXML が含まれます。

REXML ライブラリのパスは次のとおりです: rexml/document

すべてのメソッドとクラスは REXML モジュール内にカプセル化されています。

REXML パーサーには、他のパーサーと比較して次の利点があります:

  • 100% Ruby で記述されています。
  • SAX および DOM パーサーに適用できます。
  • 軽量で、2000 行未満のコードです。
  • 非常に理解しやすいメソッドとクラスです。
  • SAX2 API に基づき、完全な XPath をサポートします。
  • Ruby を使用してインストールでき、別途インストールする必要はありません。

以下はサンプルの XML コードです。movies.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) #root 要素を取得 root = xmldoc.root puts "Root element : " + root.attributes["shelf"] #以下は映画のタイトルを出力します xmldoc.elements.each("collection/movie"){ |e| puts "Movie Title : " + e.attributes["title"] } #以下はすべての映画のジャンルを出力します xmldoc.elements.each("collection/movie/type") { |e| puts "Movie Type : " + e.text } #以下はすべての映画の説明を出力します 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-like Parsing:

SAX パーサー

同じデータファイル movies.xml を処理します。小さなファイルに 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

XPath を使用して XML を調べることができます。XPath は XML 文書内で情報を検索するための言語です(参照:XPath チュートリアル)。

XPath は XML パス言語であり、XML(標準汎用マークアップ言語のサブセット)文書内の特定の部分の位置を特定するための言語です。XPath は XML のツリー構造に基づいており、データ構造ツリー内でノードを検索する機能を提供します。

Ruby は REXML の XPath クラスを通じて XPath をサポートしています。これはツリーベースの解析(ドキュメントオブジェクトモデル)です。

例

#!/usr/bin/ruby -w require 'rexml/document' include REXML xmlfile = File.new("movies.xml") xmldoc = Document.new(xmlfile) #最初の映画の情報 movie = XPath.first(xmldoc, "//movie") p movie #すべての映画のジャンルを出力 XPath.each(xmldoc, "//type") { |e| puts e.text } #すべての映画フォーマットのタイプを取得し、配列を返します 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 には 2 つの XSLT パーサーがあります。以下に簡単な説明を示します:

Ruby-Sablotron

このパーサーは正義(Masayoshi Takahash)によって作成および保守されています。これは主に Linux オペレーティングシステム向けに作成されており、以下のライブラリが必要です:

  • Sablot
  • Iconv
  • Expat

あなたは次の場所でRuby-Sablotronこれらのライブラリを見つけることができます。

XSLT4R

XSLT4R は Michael Neumann によって作成されました。XSLT4R は簡単なコマンドライン操作に使用され、サードパーティのアプリケーションが XML 文書を変換するために使用できます。

XSLT4R は 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 )

詳細情報

その他の拡張機能