2012-04-12 24 views
0

私はすべてのハッシュ値を保存したいと思うCSVを持っています。私はnokogiriサックスを使用してXML文書を解析し、それをCSVに保存しています。ハッシュをCSVに変換する

SAXパーサー:

require 'rubygems' 
require 'nokogiri' 
require 'csv' 

class MyDocument < Nokogiri::XML::SAX::Document 

    HEADERS = [ :titles, :identifier, :typeOfLevel, :typeOfResponsibleBody, 
       :type, :exact, :degree, :academic, :code, :text ] 

    def initialize 
    @infodata = {} 
    @infodata[:titles] = Array.new([]) 
    end 

    def start_element(name, attrs) 
    @attrs = attrs 
    @content = '' 
    end 
    def end_element(name) 
    if name == 'title' 
     Hash[@attrs]["xml:lang"] 
     @infodata[:titles] << @content 
     @content = nil 
    end 
    if name == 'identifier' 
     @infodata[:identifier] = @content 
     @content = nil 
    end 
    if name == 'typeOfLevel' 
     @infodata[:typeOfLevel] = @content 
     @content = nil 
    end 
    if name == 'typeOfResponsibleBody' 
     @infodata[:typeOfResponsibleBody] = @content 
     @content = nil 
    end 
    if name == 'type' 
     @infodata[:type] = @content 
     @content = nil 
    end 
    if name == 'exact'  
     @infodata[:exact] = @content 
     @content = nil 
    end 
    if name == 'degree' 
     @infodata[:degree] = @content 
     @content = nil 
    end 
    if name == 'academic' 
     @infodata[:academic] = @content 
     @content = nil 
    end 
    if name == 'code' 
     Hash[@attrs]['source="vhs"'] 
     @infodata[:code] = @content 
     @content = nil 
    end 
    if name == 'ct:text' 
     @infodata[:beskrivning] = @content 
     @content = nil 
    end 
    end 
    def characters(string) 
    @content << string if @content 
    end 
    def cdata_block(string) 
    characters(string) 
    end 
    def end_document 
    File.open("infodata.csv", "ab") do |f| 
     csv = CSV.generate_line(HEADERS.map {|h| @infodata[h] }) 
     csv << "\n" 
     f.write(csv) 
    end 
    end 
end 

ストアがフォルダ内にあるすべてのファイルのための新しいオブジェクトを作成する(47.000xmlファイル):

parser = Nokogiri::XML::SAX::Parser.new(MyDocument.new) 
counter = 0 

Dir.glob('/Users/macbookpro/Desktop/sax/info_xml/*.xml') do |item| 
    parser.parse(File.open(item, 'rb')) 
    counter += 1 
    puts "Writing file nr: #{counter}" 
end 

問題:私を得るいけない 新しい値のセットごとに新しい行が追加されます。何か案は?コードを試すため

3 xmlファイル: https://gist.github.com/2378898 https://gist.github.com/2378901 https://gist.github.com/2378904

+2

私はこのような何かを試してみてくださいもう一度言うと、 'b'モードはcsvデータで意味をなさない。 – pguardiario

答えて

3

"a"モード(以前の内容を消去するファイルを開く)でファイルを開く必要があります。

csvオブジェクトに配列を追加すると、自動的に改行が挿入されます。ハッシュ#値は値の配列を返しますが、順序を強制する方が安全です。配列を平坦にすると、列の位置がずれてしまう可能性があります([[:title1、:title2]、 'other-value']は[:title1、:title2、 'other-value']となります)。上記の変更は、以下を実行することで確認することができます

HEADERS = [:titles, :identifier, ...] 

def end_document 
    # with ruby 1.8.7 
    File.open("infodata.csv", "ab") do |f| 
    csv = CSV.generate_line(HEADERS.map { |h| @infodata[h] }) 
    csv << "\n" 
    f.write(csv) 
    end 
    # with ruby 1.9.x 
    CSV.open("infodata.csv", "ab") do |csv| 
    csv << HEADERS.map { |h| @infodata[h] } 
    end 
end 

:infodata.csvファイルが含まれています上を実行した後

require "csv" 

class CsvAppender 

    HEADERS = [ :titles, :identifier, :typeOfLevel, :typeOfResponsibleBody, :type, 
       :exact, :degree, :academic, :code, :text ] 

    def initialize 
    @infodata = { :titles => ["t1", "t2"], :identifier => 0 } 
    end 

    def end_document 
    @infodata[:identifier] += 1 

    # with ruby 1.8.7 
    File.open("infodata.csv", "ab") do |f| 
     csv = CSV.generate_line(HEADERS.map { |h| @infodata[h] }) 
     csv << "\n" 
     f.write(csv) 
    end 
    # with ruby 1.9.x 
    #CSV.open("infodata.csv", "ab") do |csv| 
    # csv << HEADERS.map { |h| @infodata[h] } 
    #end 
    end 

end 

appender = CsvAppender.new 

3.times do 
    appender.end_document 
end 

File.read("infodata.csv").split("\n").each do |line| 
    puts line 
end 

"[""t1"", ""t2""]",1,,,,,,,, 
"[""t1"", ""t2""]",2,,,,,,,, 
"[""t1"", ""t2""]",3,,,,,,,, 
+0

こんにちは、あなたのコードは私のコードのように同じことを行います。そして、新しい値のセットごとに新しい行を作成しないでください – SHUMAcupcake

+0

あなたはどのバージョンのルビーを使用していますか?ファイルモードを "ab"に変更すると、私は1.9.2p290と1.9.3-p0の両方で動作します。あなたのコードは他の場所で書き込みモードでinfodata.csvを開きますか?修正を確認するためのコードを含めるように答えを更新します。 – cydparser

+0

ruby​​ v 1.8.7を使用すると、ArgumentErrorが発生します。 'mode'は 'r'、 'rb'、 'w'、または 'wb'でなければなりません。 – SHUMAcupcake

1

私はあなたが余分なループを必要とすると思います。類似するもの

CSV.open("infodata.csv", "wb") do |csv|  
    csv << @infodata.keys 
    @infodata.each do |key, value| 
    csv << value 
    end 
end 
関連する問題