xmlのパースがしたい!nokogiri

RubyxmlやhtmlのパースするためにNokogiriの使い方を調べました。

インストール

gemからインストールできます。

gem install nokogiri

パース

・直接パース

html = "<html><body><h1>Mr. Belvedere Fan Club</h1></body></html>"

html_doc = Nokogiri::HTML(html)

xml_doc  = Nokogiri::XML("<root><aliens><alien><name>Alf</name></alien></aliens></root>") 

puts html_doc

puts xml_doc

 結果

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">

<html><body><h1>Mr. Belvedere Fan Club</h1></body></html>

<root>

  <aliens>

    <alien>

      <name>Alf</name>

    </alien>

  </aliens>

</root>

・ファイルからパース

f = File.open("test.xml")

doc = Nokogiri::XML(f)

f.close

puts doc

結果 

<?xml version="1.0"?>

<sushi>

<ikura>very good</ikura>

<saba>good</saba>

</sushi>

・urlからパース

require 'open-uri'

doc = Nokogiri::HTML(open("http://yahoo.co.jp"))

puts doc.title

 実行結果

Yahoo! JAPAN

・自動で補完する

</b>がないので通常であればエラーになるはずが、、

doc = Nokogiri::XML('<a><b>b<c>c</c></a>')

puts doc

<?xml version="1.0"?>

<a>

  <b>b<c>c</c></b>

</a>

 勝手に補完してくれます。

・パースするときのオプション

xmlの構文が間違っているときエラーにしたい場合はオプションをつけて読み込みます

doc = Nokogiri::XML('<a><b>b<c>c</c></a>') do |config|

config.strict

end

puts doc

実行するとちゃんとエラーになります

/opt/ruby-1.9.3-p545/lib/ruby/gems/1.9.1/gems/nokogiri-1.6.1/lib/nokogiri/xml/document.rb:55:in `read_memory': Premature end of data in tag a line 1 (Nokogiri::XML::SyntaxError)

        from /opt/ruby-1.9.3-p545/lib/ruby/gems/1.9.1/gems/nokogiri-1.6.1/lib/nokogiri/xml/document.rb:55:in `parse'

        from /opt/ruby-1.9.3-p545/lib/ruby/gems/1.9.1/gems/nokogiri-1.6.1/lib/nokogiri/xml.rb:33:in `XML'

        from noko.rb:43:in `<main>'

■検索

・<b></b>で囲まれたタグを取得

コード

doc = Nokogiri::XML('<a><b>b1</b><b>b2</b><c><b>b3</b></c></a>')

puts doc

puts doc.xpath("//b")

パースしたxml

<?xml version="1.0"?>

<a>

  <b>b1</b>

  <b>b2</b>

  <c>

    <b>b3</b>

  </c>

</a>

結果

<b>b1</b>

<b>b2</b>

<b>b3</b>

・特定のタグを取得

コード

doc = Nokogiri::XML('<a><b>b1</b><b>b2</b><c><b>b3</b></c></a>')

puts doc

puts doc.xpath("/a/b")[1]

 パースしたxml

<?xml version="1.0"?>

<a>

  <b>b1</b>

  <b>b2</b>

  <c>

    <b>b3</b>

  </c>

</a>

 結果

<b>b2</b>

・値を取得

コード

doc = Nokogiri::XML('<a><b>b1</b><b>b2</b><c><b>b3</b></c></a>')

puts doc

puts doc.xpath("/a/b")[1].inner_text

パースしたxml 

<?xml version="1.0"?>

<a>

  <b>b1</b>

  <b>b2</b>

  <c>

    <b>b3</b>

  </c>

</a>

結果 

b2

・属性値を取得

コード

doc = Nokogiri::XML('<a><b>b1</b><b src="src_b2">b2</b><c><b>b3</b></c></a>')

puts doc

puts doc.xpath("/a/b")[1].attr("src")

 

 パースしたxml

<?xml version="1.0"?>

<a>

  <b>b1</b>

  <b src="src_b2">b2</b>

  <c>

    <b>b3</b>

  </c>

</a>

 結果

src_b2

■変換

・値の変更

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c></a>')

puts doc

b = doc.at_css "b"

b.content = "bbbb"

puts doc

 変換前

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

</a>

 変換後

<?xml version="1.0"?>

<a>

  <b>bbbb</b>

  <c>c</c>

</a>

・ノードの移動

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c></a>')

puts doc

b = doc.at_css "b"

c = doc.at_css "c"

b.parent = c

puts doc 

 変換前

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

</a>

 

 変換後

<?xml version="1.0"?>

<a>

  <c>c<b>b</b></c>

</a>

・ノード移動2

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c></a>')

puts doc

b = doc.at_css "b"

c = doc.at_css "c"

c.add_next_sibling(b)

puts doc

変換前 

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

</a>

 変換後

<?xml version="1.0"?>

<a>

  <c>c</c>

  <b>b</b>

</a>

・属性の追加

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c></a>')

puts doc

b = doc.at_css "b"

b['img'] = "bbb.img"

puts doc

変換前

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

</a>

変換後

<?xml version="1.0"?>

<a>

  <b img="bbb.img">b</b>

  <c>c</c>

</a>

・ノードの追加

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c></a>')

puts doc

d = Nokogiri::XML::Node.new "d", doc

d.content = "ddddd"

c = doc.at_css "c"

c.add_next_sibling(d)

puts doc

変換前 

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

</a>

 変換後

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

  <d>ddddd</d>

</a>

・ラップする

コード

doc = Nokogiri::XML('<a><b>b</b><c>c</c><d>d</d></a>')

puts doc

nodes = doc.css "b,c"

wrapper = nodes.wrap("<test></test>")

puts doc

 

 変換前

<?xml version="1.0"?>

<a>

  <b>b</b>

  <c>c</c>

  <d>d</d>

</a>

 変換後

<?xml version="1.0"?>

<a>

  <test>

    <b>b</b>

  </test>

  <test>

    <c>c</c>

  </test>

  <d>d</d>

</a>

こんな感じでいろいろできます。 

トラブルシューティング

エラー

libexslt.so.0: cannot open shared object file: No such file or directory

対処法:libxsltをインストールする

sudo yum install libxslt