いつからか、以下のようなメッセージでクラッシュしたりしなかったり、という事象が出始めた。
[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"]
}
>> Home