rubyで、XMLファイルを読み込むために、REXMLを用いて読み込みをするモジュールを作ったのですが、XMLファイルによって以下のようなエラーが出てしまいます。
[実行コード](抜粋)[実行結果](抜粋)xml=File.open(filename)
doc = REXML::Document.new(xml)
No close tag for /company/shows/show/cast
Line: 13
Position: 970
Last 80 unconsumed characters:
REXML::ParseException
XMLのタグが正当についておらず、エラーになっている様子。
ちなみに環境は以下のような感じ。
- OS:OSX(Yosemite)
- Ruby:2.2.4
- XMLファイル:ウィンドウズ上のXMLエディタで作成(Windowsのエンコードで保存)
最初は、単純に該当の部分のXMLファイルをエディタで直せば解消するかとも思ったのですが、エディタで開いて見る限りはちゃんとタグは閉じている。
Windowsで作成したファイルの読み込みだったので、エンコーディングの問題を疑ったのですが、それなら全ファイルが引っかかるはずだしと色々ネットで、エンコーディング以外の問題を探ったのですが見当たりませんでした。
■Windowsで作成されたファイルは、文字コードが2つある。
色々、思い悩んだ末、エラーなく取り込めるXMLファイルと取り込めないXMLファイルの文字コードをUNIXのツールNKFで、文字コードを確認してみることにしました。(nkfのmacへのインストールが必要でした)
[取り込みがうまくいくXMLの場合]
$ nkf -g seikou.xml
Shift_JIS
[取り込みがうまくいかないXMLの場合]
$ nkf -g shippai.xml
CP932
同じWindows環境で同じツールで作成したXMLファイルであっても、文字コードが2種類あり、どうやら後者の「CP932」と出るほうがパースがうまくいかない様です。
rubyは2.0になって以降はあまりエンコーディングで悩むことがなく、割りと良きに計らって(自動で)外部エンコーディングを判断してくれているようですが、CP932についてはうまくできないようです。File.Openの際の引数指定色々やってみましたが、どうしてもうまく取り込みができません。
■かなり力技で解決しました。
取り込み対象のXMLファイルを全てUTF-8形式に変換することも考えたのですが、Windows上からこれからも更新したり増えたりすることがある上、他のプログラムにも影響を及ぼしそうなので、踏みきれませんでした。
絶対やりかた間違っている気がするのですが、結局以下のように、一旦一時ファイルの形で、ファイルを保存し、そのファイル名を返却するclassを作成しました。
# encoding:UTF-8 # Converter Class #2015/12/30 #S-JISの形式のファイルをUTF-8に変換して読み込む為のクラス require 'nkf' class Converter def convert(filename) File.open(filename) do |file| @contents=NKF.nkf('-w',file.read) @contents.gsub!('Shift_JIS','UTF-8') @contents.gsub!('shift_jis','UTF-8') end File.write('data/tempfile.tmp',@contents) return 'data/tempfile.tmp' end end
XML内にencodingを指定している所があったため、そちらもUTF-8に書き換えてます。
元のclassでは、ファイルを受け取ったら一度、このクラスをコールして変換後のファイルを受け取って、REXMLでパースする形にしました。
[元のクラスの該当箇所](抜粋)
converted_filename=@converter.convert(@filename) xml=File.open(converted_filename) doc = REXML::Document.new(xml)
おかげで、問題なくXMLのがパースできるようになりました。
絶対…間違っている気がする…orz