rubyの最近のブログ記事
libxml-rubyのAPIの変更に気がつかずにはまったので、リリースをウォッチしようとRubyForgeのページを確認するも、フィードが見つからない(あったりして)。
RubyForge全体のnewsのフィードと、プロジェクトのnewsのフィードはあった。
だけどリリースとnewsは連動しているわけではないらしく投稿するかしないかは管理者次第のようだ。
やりたいこと
リリースノートの内容は、<pre>の中身でざくっと指定できたのでLoop+Fetch Pageの結果をdescriptionにassign。
日時をフィードのpubDateにどう反映するのかがまたよくわからなくて、他の人のPipesを参考にLoop+Date Builderでitem.y:publishedにassignした。フィード出力の時点でpubDateに突っ込まれるようだ。
ようやく出来たのが↓のPipes。Livedoor Readerに食わせてウォッチ中。
http://pipes.yahoo.com/pipes/pipe.info?_id=78e1182d42024a179dfda9fc6f708550
面白いしすごく便利だけど、やりたいことをPipes流の発想に変換するのがなかなか大変。。。
YQLを使えばXPathでスクレイピング可能なのが救い。
RubyForge全体のnewsのフィードと、プロジェクトのnewsのフィードはあった。
だけどリリースとnewsは連動しているわけではないらしく投稿するかしないかは管理者次第のようだ。
RubyForge: LibXML: ニュースじゃあPipesでも使ってみるかと気軽に始めたのだけどかなり手間取った。
RubyForge: LibXML: ファイルリスト
やりたいこと
- libxml-rubyのリリース(「libxml-ruby-0.9.8」「libxml-ruby-0.9.7」部分)を抜き出してフィードに。
- descriptionに上記文字列のリンク先(リリースノート)の内容を入れる
select * from html得られたtrリストの直下の一番目のtdと二番目のtdを指定する方法でまた悩む。
where
url="http://rubyforge.org/frs/?group_id=494"
and
xpath="/html/body/div[3]/table/tr/td[2]/table/tr[position()>=4 and td/p/strong/text()]"
item.td.0.p.strong.a.href →linkてな感じ。
item.td.0.p.strong.a.content →title
item.td.1.p.strong →日時
リリースノートの内容は、<pre>の中身でざくっと指定できたのでLoop+Fetch Pageの結果をdescriptionにassign。
日時をフィードのpubDateにどう反映するのかがまたよくわからなくて、他の人のPipesを参考にLoop+Date Builderでitem.y:publishedにassignした。フィード出力の時点でpubDateに突っ込まれるようだ。
ようやく出来たのが↓のPipes。Livedoor Readerに食わせてウォッチ中。
http://pipes.yahoo.com/pipes/pipe.info?_id=78e1182d42024a179dfda9fc6f708550
面白いしすごく便利だけど、やりたいことをPipes流の発想に変換するのがなかなか大変。。。
YQLを使えばXPathでスクレイピング可能なのが救い。
ふと気づいたらlibxml-rubyが0.9.8になってた。
gemで0.8.3からupdateしたら動かないスクリプトが出てきた。
XML::Document#to_s がエラーになる。
CHANGESを見ると
前者はともかく後者は面倒だなー。というのもjrubyでも使うスクリプトなのでtransformer.setOutputProperty(javax.xml.transform.OutputKeys::ENCODING, エンコード名な文字列) とI/Fを合わせて文字列指定で作ってたから。
libxml-rubyのマニュアルによればエンコード名文字列から定数を得るI/Fがあるみたいなんだけど、どうも期待した結果にならない。
(マニュアル上はInput.s_to_encoding("UTF_8") なんだけどext/libxml/ruby_xml_encoding.cを見るとfrom_sのようで混乱する)
とりあえず文字列をいじくって定数名とみなしてお茶にごす。
alias名が困るなー
環境
- CentOS 5.2 i686
- libxml2: 2.6.26-2.1.2.7
- ruby: 1.8.5-5.el5_2.6
- rubygems: 1.3.1
- libxml-ruby: 0.9.8 (gem)
gemで0.8.3からupdateしたら動かないスクリプトが出てきた。
XML::Document#to_s がエラーになる。
CHANGESを見ると
- 出力オプションをHash指定に変えた
- エンコード名を文字列指定からLibXML::XML::Encoding下の定数指定に変えた
前者はともかく後者は面倒だなー。というのもjrubyでも使うスクリプトなのでtransformer.setOutputProperty(javax.xml.transform.OutputKeys::ENCODING, エンコード名な文字列) とI/Fを合わせて文字列指定で作ってたから。
libxml-rubyのマニュアルによればエンコード名文字列から定数を得るI/Fがあるみたいなんだけど、どうも期待した結果にならない。
(マニュアル上はInput.s_to_encoding("UTF_8") なんだけどext/libxml/ruby_xml_encoding.cを見るとfrom_sのようで混乱する)
$ irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'libxml'
=> true
irb(main):003:0> LibXML::XML::Encoding.from_s("UTF_8")
=> -1
irb(main):004:0> LibXML::XML::Encoding.from_s("UTF-8")
=> false
irb(main):005:0> LibXML::XML::Encoding.from_s("utf8")
=> false
irb(main):006:0> LibXML::XML::Encoding.from_s("utf-8")
=> false
irb(main):007:0> LibXML::XML::Encoding.from_s("utf_8")
=> -1
irb(main):008:0>
とりあえず文字列をいじくって定数名とみなしてお茶にごす。
alias名が困るなー
const_name = encoding_name.gsub(/-/, "_").upcase
encoding = LibXML::XML::Encoding.const_get(const_name)
doc.to_s(:encoding => encoding)
環境
- CentOS 5.2 i686
- libxml2: 2.6.26-2.1.2.7
- ruby: 1.8.5-5.el5_2.6
- rubygems: 1.3.1
- libxml-ruby: 0.9.8 (gem)
ふと、libxml-ruby本家を確認したら、いつのまにか0.8.3になってた。
RubyForge: LibXML: ファイルリスト
7月に入ってから怒涛のupdate
jruby+Java DOMに逃げてなんとかやりすごしていたのだけど、これは期待できるか?と再チャレンジ。
とりあえず自分ところのアプリの範囲では「[BUG] object allocation during garbage collection phase」で落ちることがなくなった。
I/Fをlibxml-rubyのままにしておいて正解だった。単にCRubyで実行しただけ。
やはりlibxml2の性能は魅力。
OS: CentOS 5.2
ruby: 1.8.5
libxml2: 2.6.26
libxml-ruby: 0.8.3
RubyForge: LibXML: ファイルリスト
7月に入ってから怒涛のupdate
jruby+Java DOMに逃げてなんとかやりすごしていたのだけど、これは期待できるか?と再チャレンジ。
とりあえず自分ところのアプリの範囲では「[BUG] object allocation during garbage collection phase」で落ちることがなくなった。
I/Fをlibxml-rubyのままにしておいて正解だった。単にCRubyで実行しただけ。
やはりlibxml2の性能は魅力。
OS: CentOS 5.2
ruby: 1.8.5
libxml2: 2.6.26
libxml-ruby: 0.8.3
gemでlibxml-ruby(0.5.4)をインストールして使っていた。
いつからか、以下のようなメッセージでクラッシュしたりしなかったり、という事象が出始めた。
新しいrubyだと問題を検出して[BUG]を出す、ということだそう。
原因はわかったが、とりあえず手元のlibxml-ruby前提で書いたツールをどうするか。
libxml-rubyのパッチを書く?
とコードを眺めたものの早々にあきらめた。これはすぐにどうこう出来そうもない。。
REXMLで書き直す?
そもそもREXMLが遅いので、libxml-rubyにしただけにこれは避けたい。
perlのLibXMLで書き直す?
んー、時間もかかるし同じものをもう一回書くのもな。
で、jruby
REXMLを使うとスタート地点に戻ってしまうので、javaのDOM・XPath APIを使うことに。
とりあえず、libxml-rubyで使ってるインタフェースだけラッパーを用意。
ツール側のコードはほぼ変更がなかった。
libxml2の軽快さには遠いがjrubyありがとうって感じ。
jruby:1.1.2
Sun Java: 1.6.0_05
OS:CentOS 5.1
いつからか、以下のようなメッセージでクラッシュしたりしなかったり、という事象が出始めた。
[BUG] object allocation during garbage collection phase・・・という問題に悩んでいたのだけど、そのものズバリの答えが。
[ruby-dev:35157] Re: error: Ruby 1.8.7 object allocation during garbage collection phaseクラッシュといっては心外な話しか。
新しいrubyだと問題を検出して[BUG]を出す、ということだそう。
原因はわかったが、とりあえず手元のlibxml-ruby前提で書いたツールをどうするか。
libxml-rubyのパッチを書く?
とコードを眺めたものの早々にあきらめた。これはすぐにどうこう出来そうもない。。
REXMLで書き直す?
そもそもREXMLが遅いので、libxml-rubyにしただけにこれは避けたい。
perlのLibXMLで書き直す?
んー、時間もかかるし同じものをもう一回書くのもな。
で、jruby
REXMLを使うとスタート地点に戻ってしまうので、javaのDOM・XPath APIを使うことに。
とりあえず、libxml-rubyで使ってるインタフェースだけラッパーを用意。
ツール側のコードはほぼ変更がなかった。
libxml2の軽快さには遠いがjrubyありがとうって感じ。
jruby:1.1.2
Sun Java: 1.6.0_05
OS:CentOS 5.1
$KCODE='u'
require 'java'
class WrapNode
attr_reader :node
def initialize(e)
@node = e
@xpath = nil
end
def to_s
@node.nodeValue.to_s
end
def wrap(e)
if e == nil
return nil
end
WrapNode.new(e)
end
def next
self.wrap(@node.nextSibling)
end
def text?
@node.nodeType == org.w3c.dom.Node::TEXT_NODE
end
def [](name)
@node.getAttribute(name)
end
def parent
self.wrap @node.parentNode
end
def child
self.wrap @node.firstChild
end
def xpath
if !@xpath
factory = javax.xml.xpath.XPathFactory.newInstance()
@xpath = factory.newXPath()
end
@xpath
end
def find(expr)
nodelist = self.xpath.evaluate(expr, @node, javax.xml.xpath.XPathConstants::NODESET)
ret = []
for i in 0 .. (nodelist.length - 1)
ret.push(WrapNode.new(nodelist.item(i)))
end
ret
end
end
class WrapDocument < WrapNode
def initialize(e)
super(e)
end
def root
self.wrap(@node.documentElement)
end
end
# 指定されたファイルをopenしてXML文書を返す
#
# fn_in::
# ファイル名。nilの場合、stdinを適用
def build_doc(fn_in)
st = java.lang.System.in
if fn_in
st = java.io.FileInputStream.new(fn_in)
end
factory = javax.xml.parsers.DocumentBuilderFactory.newInstance()
builder = factory.newDocumentBuilder()
WrapDocument.new(builder.parse(st))
end
doc = build_doc("foo.xml")
doc.find("//bar").each { |e|
puts e["name"]
}
