LibXML-Rubyの使い方メモ

以前にLibXML-Rubyのインストールメモを書いてから、大分時間がたってしまったけれども。
ぽつぽつと色々使ってなんとなく分かってきてるので、初歩の使い方を簡単に纏めてみるです。
なにしろ、時間が経つとまた忘れるから><

ちなみに「なにこれ、ここまでは知ってる!」
っていう方はドキュメントへのリンクを置いておきますので、これで許してください><
http://libxml.rubyforge.org/rdoc/index.html

LibXML-Rubyを使う

なにはともあれ、LibXML-Rubyを使うにはまず読み込んでから。
※ちなみにインストールは以前の記事参照で。(libxml-rubyをinstallしてみたメモ

require 'rubygems'
require 'xml/libxml' 

外部のXMLを読み込んだりする場合はopen-uriとかもrequireしておくと幸せになれるかも。

require 'open-uri'

XMLの生成と保存

LibXML-Rubyで新しいXMLを作成したいので、まずは雛形になるXMLを生成してみる

<?xml version="1.0" encoding="UTF-8"?>
<Root/>

こんな感じにとりあえずしたい
ソースが以下な感じ

xml = LibXML::XML::Document.new()
xml.root = LibXML::XML::Node.new( 'Root' )
root = xml.root

もしも、外部のXMLをopen-uriで取得する場合は以下のような感じ

uri = open( 'hogehoge.xml' ) do |f|
  f.read
end
xml = LibXML::XML::Document.string( uri )

生成したXMLを保存してみる

save_dir = 'hoge/hige'
xml.save( save_dir + '/hogehoge.xml', :indent => true, :encoding => LibXML::XML::Encoding::UTF_8 )

内部情報の生成

エレメントと属性の追加を行うには

xml = LibXML::XML::Document.new()
xml.root = LibXML::XML::Node.new( 'Root' )
root = xml.root
root << elem1 = LibXML::XML::Node.new( 'Element1' )
elem1['type'] = 'hoge'
elem1 << 'hige'

生成されたXMLは以下

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <Element1 type="hoge">hige</Element1>
</Root>

もしも異なるXMLのノードを追加する場合は、以下のように追加する感じ
※そのまま追加しようとすると'Nodes belong to different documents.'になっちゃう

xml_add = LibXML::XML::Document.new()
xml_add << root = xml.copy( true ) # falseの場合はdeepcopyされない

もしも特定のエレメント、またはノードのみをコピーする場合は以下のように追加

root << elemnt = xml.find_first( 'Element1' ).copy( true ) # falseの場合はdeepcopyされない

もしも特定のノードを削除する場合は、以下のような感じ
※例えばrootに含まれるノードのうち、アトリビュートにtypeが存在し、かつ値がhogeの場合にノードを削除する

xml.find( '*' ).each do |node|
  node.attributes.each do |attr|
    if( attr.name == 'type' && attr.value == 'hoge' ) then
      node.remove!
      break
    end
  end
end

内部情報の取得

エレメントの検索及び値の取得してみる
※直接find又はfind_firstからcontetを取得しようとした時、もしも値がない場合NoMethodErrorになるので注意

xml.find_first( 'hoge/hige' ).each do |elem|
  if elem.name == 'hage_element'
    p elem.content
  end
end

上記と結果は同じ

p xml.find_first( 'hoge/hige/hage_element' ).content

属性を取得してみる

xml.find( 'hoge' ).attributes.each do |attr|
  if attr.name == 'type'
    p attr.value
  end
end

上記と結果は同じ

p xml.find_first( 'hoge' ).attributes.get_attribute( 'type' ).value


と、基本的な使い方はこんな感じなのかな。かな。
突っ込みとか追加情報募集中ですます。

Javaランタイムバージョンを落としたい!

久しぶりにしぃのお絵かきにお呼ばれしけり。
と思ったら、ペンで書いて消せない!
消せないし、スクロールしても反応がNothing!
どうやらJavaランタイムがいい感じに全力アップデートされてる模様。
ということでバージョンを落とします。

Javaランタイムのバージョンを落とす

現在のバージョンを確認する

まずはタスクバーからバージョンを確認してください。
右クリックすると以下のようなメニューがでてきます。

Ver1.6.9_13になっていればおk。
もしもそれよりもVerが上だと、正常動作しません。

利用するランタイムのバージョンを指定する

バージョンを下げるには、コントロールパネルを開くを選択してください。
開くとタブが[基本][アップデート][セキュリティ][詳細]と並んでると思います。

確認をしたらJavaを選んでください。
するとJavaRuntimeEnvironment設定が表示されます。
次に表示ボタンを押します。

すると、利用可能な一覧がでてきます。
※もしもここの一覧に1.6.0_13が存在しない場合、以下の2段目のリンク”JRE 6u13”からダウンロードしインストールしてください。
http://java.sun.com/products/archive/j2se/6u13/index.html
ここで1.6.0_13以外は有効のチェックを外してしまいましょう。

適用から再起動

了解を押したら設定画面にもどり、適用(A)を選択します。

最後に再起動をしておわり。

これで楽しいしぃタイムが復活ですね!!

railsのコントローラをcronから実行するには

事の発端は、がりがり実装していたコントローラのメソッドをクーロンからも実行したいという感じ。
いくつか調べてみるとrailscronとか、いくつかの方法でmodelは叩ける。
けどcontrollerは「wgetすれば?」という感じ?なのかしら。
それはなんかイヤだし、modelに移すのもね。

で、色々と調べてみると、かなり盛り上がってる記事を発見!
http://matthall.wordpress.com/2006/12/06/how-to-execute-a-rails-controller-action-via-cron/
読んでみるとなるほど簡単で、runnerにActionControllerを指定して叩いてあげればいいみたい。

$ script/runner -e development "app = ActionController::Integration::Session.new; app.get 'account/index'"

※app/controllers/account_controller.rb (method:index)

ただ、気をつけないといけないのは、config/environment.rbにaction_controllerを呼び込んであげないと、
「誰それ?controller?知らない。」
みたいなツンツンした反応が返ってくる。
ので、config/environment.rbの一番下に以下を追記。
※enviroment.rbを編集したら必ず再起動を忘れずに!

require 'action_controller/integration'

これでデレてくれます。
あとはcronですね。
crontab -eコマンドで編集を行い、完了したらcrontab -lでチェックをかけます。

$ crontab -e
# 追記内容
 /絶対パス/ruby /RAILSルート/script/runner "app = ActionController::Integration::Session.new; app.get 'sim_all/index'"
$crontab -l

以上。
本当はrailsの中で完結してもいいナァと思っていたんですが、既にcrontabもでっぷりしてきていたし。まぁこれで良いか。

RubyOnRailsでfindしたオブジェクトからkeyとvalueをeachで取得するには

もちろんわかってる人には当たり前なんだろうケド、わかってなかった。。。
のでメモ。

RubyOnRailsで例えば以下のように取得したデータから、keyと対応するvalueを引っ張り出したい。

users = User.find( :all, :conditions => ['id = 1'] )

これを全力でeachしたかったけど、undefined method `each`とか言われる。
てっきりずっとhashだとばかり思ってたので、each_pairとかさも当然のように実行してundefined method `each_pair`。
あ、ウン。
どうもちゃんとソースを追ってみると、オブジェクトで返してる。

ので、結論としてはこんなかんじ。

users = User.find( :all, :conditions => ['id = 1'] )
users.attributes.each do |k, v|
  p "key   = #{k}"
  p "value = #{v}"
end

なるほど、attributes.eachですよね。

昨日の夜は時間がなかったから直指定を全速前進で、かなりの行書いちゃったから今から全部書き直し。
5行くらいになる気がしま・・・すorz

RubyOnRailsでfindする時、conditionsにArrayを渡すメモ

RubyOnRailsでfindするSQLを組み立てる際、複数の自動生成されるキーをconditionsに渡そうとして詰まったのでメモ書き。
最終的に作りたいfind文は以下。

User.find( :all, conditions => [ 'id IN ( ?, ?, ?, ?, ? )', 2, 4, 5, 8, 9 ] )

ユーザからのリクエストで、以下のようなid郡を配列で受けてます。
idは実際は特殊なもので、エスケープの必要な文字を含んでいる状態。
なので、?で置き換えて処理してもらいたい感じ。

id = [ 2, 4, 5, 8, 9 ]

これをうまくconditionsに当てはめたい。
結果できたスパゲッティーは以下。

if ( id.size != 0 ) then
  rep_ar = []
  # idの件数分'?'を追加
  for i in 0..( ( id.size ) -1 )
    rep_ar << '?'
  end
  User.find( :all, conditions => ["id IN ( #{rep_ar.join( ',' )} )", *id] ).each do |h|
    p h[:id]
  end

ミソだったのは*(アスタリスク)!
まさかこんな便利だったとは。
呼び出し側のアスタリスクは配列を展開しますが、受け取り側のアスタリスクは残りの引数を配列化してくれるそうな。
あやうくスパゲッティーを超えて、乾燥しはじめたソウメンになるところでした。

libxml-rubyをinstallしてみたメモ

portable Ubuntuでlibxml-rubyをインストールしたら、凄い躓いたのでメモを。

と、思ったけど長いからまず結論。

結論として

$ sudo apt-get install libxslt1-dev
$ sudo apt-get install libxml2-dev
$ sudo apt-get install ruby1.8-dev
$ sudo gem update --system
$ sudo gem1.8 install libxml-ruby

これで動きまス。

んで、以下作業ログ。

作業ログ

まぁ、一発で入るでしょ!凄いよgem!!

$ sudo gem install libxml-ruby
Bulk updating Gem source index for: http://gems.rubyforge.org
....

オウフ
止まった。。。
仮想環境のメモリが256だとgemがメモリに展開して処理するには足りないみたい。
なので、confを編集して512へ引き上げてから再実行。

$ sudo gem install libxml-ruby
Gem files will remain installed in /var/lib/gems/1.8/gems/libxml-ruby-1.1.3 for inspection.
Results logged to /var/lib/gems/1.8/gems/libxml-ruby-1.1.3/ext/libxml/gem_make.out

まだだめ。
依存関係のライブラリがあるようで、gemからのlibxml-rubyを単体でインストールしようとしてもダメらしいデス。
しょうがないからそっちも探してインストール。
どうやらlibxslt1-devとlibxml2-devという開発用のパッケージをapt-getすればいいみたい。

$ sudo apt-get install libxslt1-dev
$ sudo apt-get install libxml2-dev
$ sudo gem install libxml-ruby
Select which gem to install for your platform (i486-linux)
 1. libxml-ruby 1.1.3 (ruby)
 2. libxml-ruby 1.1.3 (x86-mswin32-60)
 3. libxml-ruby 1.1.2 (x86-mswin32-60)
 4. libxml-ruby 1.1.2 (ruby)
 5. Skip this gem
 6. Cancel installation
> 1
Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.
ruby extconf.rb install libxml-ruby
extconf.rb:14:in `require': no such file to load -- mkmf (LoadError)
	from extconf.rb:14

まだだめ。
mkmfがLoadError?
それっぽい記事をみつけたので試してみる

$ sudo gem install why-hpricot --source http://gems.github.com
Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.
ruby extconf.rb install why-hpricot --source http://gems.github.com
extconf.rb:1:in `require': no such file to load -- mkmf (LoadError)
	from extconf.rb:1

ボスケテtt
冷静になって調べるとどうもruby-develですよね、なるほど?

$ sudo apt-get install ruby-devel
E: パッケージ ruby-devel が見つかりません

ahi...
えっと?
ruby-develじゃなくて、ruby1.8-dev?
なんか魔法っぽくなってきた(おもに脳みその湯立ち具合が)
今度こそ!
ついでにgemもVerUP!

$ sudo apt-get install ruby1.8-dev
$ sudo gem update --system

gemがw
gem1.8になったw

$ sudo gem1.8 install libxml-ruby

大量にEnclosingを吐きましたがいったっぽい。。。
ドキュメント(RDOC)の問題?かな?カナ?
とりえあえずテストコード。

    xml_orig = LibXML::XML::Parser.new
    xml_orig.string = open( 'ファイルパス/test.xml' ) do |f|
      f.read
    end
    xml = xml_orig.parse
    xml.find( '対象エレメント' ).each do |node|
      p node
    end
    # ついでに保存とかもしちゃう
    xml.save('./output.xml', :indent => true, :encoding => LibXML::XML::Encoding::UTF_8)

問題なく動いた!!
細かい使い方はこちらからで。
http://libxml.rubyforge.org/rdoc/index.html
と、簡単な使い方をまとめてみました!
とりあえず動かしてみる!
という方は参照ください〜。

以上お疲れ様でした〜><

追記(20090731)

エントリ内の記述”XML::”呼び出しにおいて、XML::からはじめてしまうと、以下のようなNameErrorが出てしまい、処理が止まってしまっていました。
NameError (uninitialized constant XML::Document):
(必ずという訳ではなく、条件があるようですが、把握できていません)
よって、エントリ内の全てを以下のように書き換えました。
XML:: -> LibXML::XML::

Portable Ubuntuを落としてきてやったこと〜rails導入編

唐突ですが、自宅PCにPortable Ubuntuを入れて遊ぼう!ということで!!
若干というかだいぶ乗り遅れている気もしないではないですがその辺りつっこみはなしでお願いしまス。

なにはともあれ本体をDLするところからですよね。
まずは本体を取得してきます。
http://portableubuntu.demonccc.com.ar/
ちなみにボクはSourceforge.netから。

さっくり解凍して"run_portable_ubuntu.bat"を起動します。
問題なく起動することを確認したら、ディスク容量を増やしますです。
さすがに1.8GBは少なすぎるので。
作業にあたり、以下を参考にしました。多謝。
http://portable-ubuntu.of-jp.com/settings/image_disc2/
打ち込んだコマンドはこんな感じ。
Windowsコンソール上

cd Portable Ubuntuのあるフォルダ\Portable_Ubuntu\images
fsutil file createnew rootfs_.img 17179869184

□confファイル編集

#cobd3="D:\Documents and Settings\czw5hv\Application 〜省略〜 # コメントアウト
cobd3=images\rootfs_.img # 追加行

Ubuntuを起動しターミナルから

> sudo su #パスワード入力
> dd if=/dev/cobd0 of=/dev/cobd3
> fsck.ext3 -f /dev/cobd3
> resize2fs -f /dev/cobd3

※パスワードは変更をしていない初期状態だと123456です
で、既存のrootfs.imgを削除してrootfs_.imgをrootfs.imgへ。

それと仮想メモリを増量行っておきます。(インストールフォルダ\config\portable_ubuntu.conf)

#mem=256
mem=512

ここで仮想環境のメモリを増量行っていない場合、ruby-gemを実行した際、以下のようなメッセージのまま止まってしまう現象に悩まされることになります。

Bulk updating Gem source index for: http://gems.rubyforge.org


ここまできたら、細かいところをちょろちょろ。
とりあえず時間帯域を変えます。
バーに日時が表示されていますが、そこを選択。
LocationのプルダウンからEditボタンを押してLocationをAddします。
・・・なんかTokyoでいいのがないんですが、まぁTokyoInternationalAirportでいいかな。
TokyoHeliportってどこだっけ。
これで時間表記がいい具合になりました。
あとはLanguageタブから日本語を設定して、アップデートもかけて、と。

次にapt-getを更新してから、railsを動かせるようにしましょう。
こちらもいたって単純。全てapt-get installでいきます。

> sudo apt-get update 
> sudo apt-get upgrade 
> sudo apt-get install rails
> sudo apt-get install emacs
> sudo apt-get install mysql-client mysql-server
> sudo apt-get install git-core
> git config --global user.name "username"
> git config --global user.email "mailaddress@xxx.xxx"
> git config --global color.ui auto

え?emacsがなくてどうやってソースを書けと?
※ちなみに.emacsは今の仕事で使ってる開発環境と同様のものを作っています!是非皆さんもMy.Emacsを作ってみてください!
それに忘れてはいけないのがDB!と、gitですね!

で、とりあえずPublicフォルダへ移動してプロジェクト生成とDBの作成。
configフォルダのdatabase.ymlにユーザとパスワードを記入して起動、と。
ちなみにdatabase.ymlを書き換え忘れてエラーが出たのは、きみとぼくだけの秘密DA☆
(DBはとりあえず対応するDBの生成後匿名ユーザを削除し、専用のユーザ'rails'を作成しています。
最後にrakeコマンドでDBとの接続を確認し、もしもここでエラーが出たらdatabase.ymlを再確認してください。)

> rails boards
> cd boards
> ruby script/server

> mysql -u root -p
mysql> create database boards;
mysql> show databases;
mysql>  grant all privileges on boards.* to 'rails'@'localhost' identified by 'パスワード文字列' with grant option;
mysql> \q;

> rake db:migrate

んで、http://localhost:3000でアクセス。
おkおk。

ここで後々使うこともある(?)のでopen-uriライブラリにパッチをあてておきます。
(細かい内容はソース嫁ですが、open-uri.rbのLine102-116,128-131が追記されてLine95,99で引き数へ追加と非常にシンプルです。更に気になる方は”open-uriは便利だがGETしかできないので何とかする話”こちら参照されるとよいかも。)
ライブラリにパッチ!!といっても非常に単純で、以下コマンドでいけます。

$ cd /mnt/C/Ruby/src/ruby-1.8.6-p287/lib
$ wget http://rubyforge.org/tracker/download.php/426/1700/6321/890/diff-1.8
$ sudo apt-get install patch
$ patch open-uri.rb diff-1.8

これは素晴らしくお手軽にHTTP通信をこなしてくれるopen-uriライブラリに、折角だしPOSTとかPUTとか色々サポートして欲しい!というような感じ。で。
完全にわき道ですが、もしもサーバ環境等でパッチとか無理!ていうかそのあたりは触れないんだよ!
という場合は以下のような感じで実装するといいかも?dis待ちちゅ><

private
  def open_post_uri( url, type, value )
    uri = URI.parse( url )
    Net::HTTP.start( uri.host, uri.port ){ |http|
      # create request instance
      request = Net::HTTP::Post.new( uri.path )
      # header
      request['user-agent'] = "Ruby/#{ RUBY_VERSION } HttpClient"
      # body( The second argument can be omitted. )
      request.set_form_data( { type => value }, '&' )
      # send
      response = http.request( request )
      return response.body
    }
  end

以上環境はこんな感じで!
次回はここから簡単なアプリケーションを作ろうと思います!!
がんばろう。