1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

RubyのXMLデータパースライブラリ「Nokogiri」の高度な使い方

2022-01-31 20:04:51


I. 基本構文
1. nokogiriオブジェクトを直接文字列として取得する。

html_doc = Nokogiri::HTML("<html><body><h1>Mr. Belvedere Fan Club</h1></body></html>")
xml_doc = Nokogiri::XML("<root><aliens><aliens><name>Alf</name></alien></aliens></ root>")


ここでは、html_docとxml_docがnokogiriのファイルです。

2. また、ファイルハンドルでnokogiriオブジェクトを取得することもできます。

f = File.open("blossom.xml")
doc = Nokogiri::XML(f)
f.close


3. また、ウェブサイトから直接入手することも可能です。

require 'open-uri'
doc = Nokogiri::HTML(open("http://www.xxx.com/"))


II. XMLファイルのパース例
XML/HTMLファイルからフィールドを取得するための一般的な方法。

今、shows.xmlというファイルがあり、次のような内容になっています。

<root>
 <sitcoms>
  <sitcom>
   <name>Married with Children</name>
   <characters>
    <character>Al Bundy</character>
    <character>Bud Bundy</character>
    <character>Marcy Darcy</character>
   </characters>
  </sitcom>
  <sitcom>
   <name>Perfect Strangers</name>
   <characters>
    <character>Larry Appleton</character>
    <character>Balki Bartokomous</character>
   </characters>
  </sitcom>
 </sitcoms>
 <dramas>
  <drama>
   <name>The A-Team</name>
   <characters>
    <character>John "Hannibal" Smith</character>
    <character>Templeton "Face" Peck</character>
    <character>"B.A." Baracus</character>
    <character>"Howling Mad" Murdock</character>
   </characters>
  </drama>
 </dramas>
</root>


すべての文字タグの中身を探したい場合は、このようにします。

@doc = Nokogiri::XML(File.open("shows.xml"))
@doc.xpath("//character")


xpath および css メソッドは、配列に似たノードのリストを返します。その内容は、ドキュメントのマッチングルールに一致するノードです。

dramasノードに含まれる文字ノードのリストを検索します。

@doc.xpath("//dramas//character")


より読みやすいcssメソッド。

characters = @doc.css("sitcoms name")
# => ["<name>Married with Children</name>", "<name>Perfect Strangers</name>"]


クエリ結果が一意であることが分かっている場合、リストの代わりにこの結果を直接返したい場合は、at_xpath または at_css を直接使用することができます。

@doc.css("dramas name").first # => "<name>The A-Team</name>"
@doc.at_css("dramas name") # = > "<name>The A-Team</name>"


III. 名前空間
名前空間は、複数のタグが存在する場合に非常に便利です。
例えば、こんなparts.xmlがあったとします。

<parts>
 <! -- Alice's Auto Parts Store -->
 <inventory xmlns="http://alicesautoparts.com/">
  <tire>all weather</tire>
  <tire>studded</tire>
  <tire>extra wide</tire>
 </inventory>

 <! -- Bob's Bike Shop -->
 <inventory xmlns="http://bobsbikes.com/">
  <tire>street</tire>
  <tire>mountain</tire>
 </inventory>
</parts>



ユニークなURLは、異なるタイヤタグを区別するための名前空間として使用することができます。

@doc = Nokogiri::XML(File.read("parts.xml"))
car_tires = @doc.xpath('//car:tire', 'car' => 'http://alicesautoparts.com/')
bike_tires = @doc.xpath('//bike:tire', 'bike' => 'http://bobsbikes.com/')


名前空間を使いやすくするために、nokogiriはルートノードで見つかった適切な名前空間を自動的にバインドします。
nokogiriは提供されたURLを自動的に関連付け、コードの量を減らすための慣習です。
例えば、こんなatom.xmlがあるとします。

<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Example Feed</title>
 <link href="http://example.org/"/>
 <uploaded> 2003-12-13T18:30:02Z</updated>
 <author>
  <name>John Doe</name>
 </author>
 <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>

 <entry>
  <title>Atom-Powered Robots Run Amok</title>
  <link href="http://example.org/2003/12/13/atom03"/>
  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
  <updated>2003-12-13T18:30:02Z</updated>
  <summary>Some text.</summary>
 </entry>
</feed>



上記の規約に従い、xmlnsは自動的にバインドされるため、xmlnsに手動で値を割り当てる必要はない。

@doc.xpath('//xmlns:title')
# => ["<title>Example Feed</title>", "<title>Atom-Powered Robots Run Amok</title>"]


同じ場合、cssの使い方。

@doc.css('xmlns|title')


また、CSSでは、名前空間の名前がxmlnsであれば、この単語自体も無視することができます。

@doc.css('title')