2011-10-21 142 views
12

我想使用ruby將.json文件轉換爲.csv文件。請幫我做到這一點。在ruby中將.json轉換爲.csv

也建議任何工具來實現這一點。

+0

看看這個:http://stackoverflow.com/questions/5357711/csv-to-json-ruby-script – WarHog

+0

你有JSON數據的例子嗎? JSON本身可能是多維的,而csv是二維的。 – mliebelt

回答

21

嘗試是這樣的:

require 'csv' 
require 'json' 

csv_string = CSV.generate do |csv| 
    JSON.parse(File.open("foo.json").read).each do |hash| 
    csv << hash.values 
    end 
end 

puts csv_string 
+1

不錯,簡單。 請記住,這不會考慮嵌套並假定列表中的所有對象都是相同的。 – SirLenz0rlot

8

要實際寫入文件...

require 'csv' 
require 'json' 

CSV.open("your_csv.csv", "w") do |csv| #open new file for write 
    JSON.parse(File.open("your_json.json").read).each do |hash| #open json to parse 
    csv << hash.values #write value to file 
    end 
end 
5

我覺得easies方式到JSON轉換爲CSV紅寶石中使用json2csv紅寶石的寶石。 PS:我可能會因爲我的作者而有偏見。

json2csv github repo

運行命令

json2csv convert data/sample.json 

輸入文件

在這種特定情況下它會轉換以下JSON:

cat data/sample.json 

{ 
"12345": { 
    "Firstname": "Joe", 
    "Lastname": "Doe", 
    "Address": { 
     "Street": "#2140 Taylor Street, 94133", 
     "City": "San Francisco", 
     "Details": { 
      "note": "Pool available" 
     } 
    } 
}, 

"45678": { 
    "Firstname": "Jack", 
    "Lastname": "Plumber", 
    "Address": { 
     "Street": "#111 Sutter St, 94104", 
     "City": "San Francisco", 
     "Details": { 
      "note": "Korean Deli near to main entrance" 
     } 
    } 
} 

輸出

cat data/sample.json.csv 

id,Firstname,Lastname,Address.Street,Address.City,Address.Details.note 
12345,Joe,Doe,"#2140 Taylor Street, 94133",San Francisco,Pool available 
45678,Jack,Plumber,"#111 Sutter St, 94104",San Francisco,Korean Deli near to main entrance 
+0

您好@korCZis - 我試了你的寶石,並得到以下內容:json2csv轉換errors.json NameError:未定義的本地變量或方法'錯誤'爲主:對象 從(irb):3 從/ usr/local/opt /rbenv/versions/2.1.5/bin/irb:11:in'

' – Angela

+0

你可以發佈完整的堆棧跟蹤還是給我寫郵件? [email protected] – korCZis

+0

是的,讓我再試一次.... https://github.com/korczis/json2csv/issues/2 – Angela

3

基於@Alex's answer但加入CSV頭示例測試

# utils.rb 
require "csv" 
module Utils 
    def self.array_of_hashes_to_csv(array_of_hashes) 
    CSV.generate do |csv| 
     csv << array_of_hashes.first.keys 
     array_of_hashes.each { |hash| csv << hash.values } 
    end 
    end 
end 

# utils_test.rb 
class UtilsTest < MiniTest::Unit::TestCase 
    def test_array_of_hashes_to_csv 
    array_of_hashes = [ 
     { :key1 => "value1", :key2 => "value2" }, 
     { :key1 => "value3", :key2 => "value4" } 
    ] 
    expected_result = "key1,key2\nvalue1,value2\nvalue3,value4\n" 
    assert_equal(expected_result, Utils.array_of_hashes_to_csv(array_of_hashes)) 
    end 
end 
1

將json轉換爲csv的Ruby代碼。

通過將數組轉換爲雙引號字符串來處理數組。

#json-to-csv.rb 
require 'json' 
require 'csv' 

file = File.read('./input.json') 
hash = JSON.parse(file) 

CSV.open('./output.csv', 'w') do |csv| 
    headers = hash.first.keys 
    csv << headers 

    hash.each do |item| 
    values = item.values 
    printable_values = Array.new 
    values.each do |value| 

     printable_values << value.to_s.gsub(/\[|\]/,'').gsub(/"/,'\'') 

    end 

    csv << printable_values 

    end 

end 
0

編輯:

下面描述此功能是現在可作爲gem。與gem install json_converter安裝完成後,下面的片段可以用來從有效的JSON字符串或對象生成CSV:

require 'json_converter' 
json_converter= JsonConverter.new 

# Assume json is a valid JSON string or object 
csv = json_converter.generate_csv json 

原來的答案:

如果你的JSON數據相對簡單(沒有嵌套或數組),Alex的答案可能是處理這個問題最簡單的方法。

但是,如果你需要考慮數組和嵌套對象,我試圖將這樣一個轉換器的web version端口轉移到紅寶石。它可以發現here。處理數據實際重組的方法是array_fromflatten

array_from方法嘗試識別給定數據集的「行」數據的外觀。這並不完美,您可能想要針對不同的數據集調整此部分。

# Attempt to identify what a "row" should look like 
def array_from(json) 
    queue, next_item = [], json 
    while !next_item.nil? 

    return next_item if next_item.is_a? Array 

    if next_item.is_a? Hash 
     next_item.each do |k, v| 
     queue.push next_item[k] 
     end 
    end 

    next_item = queue.shift 
    end 

    return [json] 
end 

flatten方法在JSON(多個)對象遞歸迭代,併產生表示標題和值的對象。如果對象是嵌套的,則其列的標題將以它的父鍵作爲前綴,由/字符分隔。

# The path argument is used to construct header columns for nested elements 
def flatten(object, path='') 
    scalars = [String, Integer, Fixnum, FalseClass, TrueClass] 
    columns = {} 

    if [Hash, Array].include? object.class 
    object.each do |k, v| 
     new_columns = flatten(v, "#{path}#{k}/") if object.class == Hash 
     new_columns = flatten(k, "#{path}#{k}/") if object.class == Array 
     columns = columns.merge new_columns 
    end 

    return columns 
    elsif scalars.include? object.class 
     # Remove trailing slash from path 
     end_path = path[0, path.length - 1] 
     columns[end_path] = object 
     return columns 
    else 
    return {} 
    end 
end 

如果在原來的JSON任何null的價值,您需要在嘗試轉換之前將這些轉化爲比nil其他的東西 - 你一般會擁有不平行,如果你不這樣做。該nils_to_strings方法處理的是:

# Recursively convert all nil values of a hash to empty strings 
def nils_to_strings(hash) 
    hash.each_with_object({}) do |(k,v), object| 
    case v 
    when Hash 
     object[k] = nils_to_strings v 
    when nil 
     object[k] = '' 
    else 
     object[k] = v 
    end 
    end 
end 

這裏是如何做到這一點用一個簡單的例子:

json = JSON.parse(File.open('in.json').read) 
in_array = array_from json 
in_array.map! { |x| nils_to_strings x } 

out_array = [] 
in_array.each do |row| 
    out_array[out_array.length] = flatten row 
end 

headers_written = false 
CSV.open('out.csv', 'w') do |csv| 
    out_array.each do |row| 
    csv << row.keys && headers_written = true if headers_written === false 
    csv << row.values 
    end 
end 

最後,這裏的一些例子輸入/輸出:

輸入:

{ 
    "Forms": [ 
    { 
     "Form": { 
     "id": "x", 
     "version_id": "x", 
     "name": "x", 
     "category": "", 
     "subcategory": null, 
     "is_template": null, 
     "moderation_status": "x", 
     "display_status": "x", 
     "use_ssl": "x", 
     "modified": "x", 
     "Aggregate_metadata": { 
      "id": "x", 
      "response_count": "x", 
      "submitted_count": "x", 
      "saved_count": "x", 
      "unread_count": "x", 
      "dropout_rate": "x", 
      "average_completion_time": null, 
      "is_uptodate": "x" 
     } 
     }, 
     "User": { 
     "username": "[email protected]" 
     } 
    }, 
    { 
     "Form": { 
     "id": "x", 
     "version_id": "x", 
     "name": "x", 
     "category": "", 
     "subcategory": null, 
     "is_template": null, 
     "moderation_status": "x", 
     "display_status": "x", 
     "use_ssl": "x", 
     "modified": "x", 
     "Aggregate_metadata": { 
      "id": "x", 
      "response_count": "x", 
      "submitted_count": "x", 
      "saved_count": "x", 
      "unread_count": "x", 
      "dropout_rate": "x", 
      "average_completion_time": null, 
      "is_uptodate": "x" 
     } 
     }, 
     "User": { 
     "username": "[email protected]" 
     } 
    } 
    ] 
} 

輸出:

Form/id,Form/version_id,Form/name,Form/category,Form/subcategory,Form/is_template,Form/moderation_status,Form/display_status,Form/use_ssl,Form/modified,Form/Aggregate_metadata/id,Form/Aggregate_metadata/response_count,Form/Aggregate_metadata/submitted_count,Form/Aggregate_metadata/saved_count,Form/Aggregate_metadata/unread_count,Form/Aggregate_metadata/dropout_rate,Form/Aggregate_metadata/average_completion_time,Form/Aggregate_metadata/is_uptodate,User/username 
x,x,x,"","","",x,x,x,x,x,x,x,x,x,x,"",x,[email protected] 
x,x,x,"","","",x,x,x,x,x,x,x,x,x,x,"",x,[email protected] 
0

這是句柄頭&嵌套的json。

require 'csv' 
require 'json' 

@headers = [] 
file = File.open('file.json') 
JSON.parse(file.read).each do |h| 
    h.keys.each do |key| 
    @headers << key 
    end 
end 

uniq_headers = @headers.uniq 
file = File.open('file.json') 
finalrow = [] 

JSON.parse(file.read).each do |h| 
    final = {} 
    @headers.each do |key2| 
    final[key2] = h[key2] 
    end 

    finalrow << final 
end 

CSV.open('output.csv' , 'w') do |csv| 
    csv << uniq_headers 
    finalrow.each do |deal| 
    csv << deal.values 
    end 
end