先日、Nokogiriの1.5.6がリリースされました。
このアップデートで属性アクセサーに変更があって、GitHubでもイシューが上がっています。その中でメンテナーの@flaverjonesも認めているように、これは1.5.5→1.5.6というパッチレベルリリースには相応しくないほど大きな変更です。
というか、実際僕もハマりました(余談ですがTravisがテストのこけたのを教えてくれて気付きました、改めて素晴らしいサービスだと思いました)。
ここで属性アクセサーと言っているのは、
<input type="email">
というメールアドレスフィールドがあった時に
input['type'] # => "email"
という風にアクセスして値を取れるNokogiri::XML::Node#[]
メソッドのことです。
では、どのように変化したのでしょうか、ちょっとプログラムを書いてみました。
version = ARGV.shift
gem 'nokogiri', version
require 'nokogiri'
puts Nokogiri::VERSION
doc = Nokogiri.XML(DATA.read)
nav = (doc/'nav').first
p [nav['type'], nav['epub:type']]
__END__
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<title>Table of Contents for Example Book</title>
</head>
<body>
<nav epub:type="toc">
</nav>
</body>
</html>
$ ruby noogiri-attribute.rb 1.5.5
1.5.5
["toc", nil]
$ ruby noogiri-attribute.rb 1.5.6
1.5.6
[nil, "toc"]
今まで取れていた値が取るのに、名前空間プリフィクスが必要になってしまっています。
当然、epub:type
なんて、任意の名前空間プリフィクスを使ったキーは使いたくない(環境を限定できればその限りではない)。
ではどうすればいいのか? というと、書き捨てのスクリプトはともかく、ある程度長く使うことが分かっているものは、#[]
の代わりに#attribute_with_ns
を使うのがいいかなあと思っています。
ns_uri = 'http://www.idpf.org/2007/ops'
nav = (doc/'nav').first
attr = nav.attribute_with_ns('type', ns_uri)
type = attr.nil? ? nil : attr.value # attr.to_sでいいことも多いけど、nilと空文字列""を区別したいこともある
p type # => 1.5.5でも1.5.6でも"toc"
他にいいメソッド見付けたら教えてください!
ま、XML名前空間を使った属性アクセスなんて、している人殆どいないでしょうけど……。