Json到csv。如何转换它?

时间:2017-12-21 18:26:14

标签: ruby-on-rails ruby

我遇到了将Json(带有嵌套值)转换为CSV文件的麻烦(我希望第一行的标题和下面的json值)。 我几乎做到了,但我的输出中仍然存在一些问题。 我写了迄今为止所做的一切,希望能让你的工作变得更轻松。

这是json:

[
  {
    "id": 0,
    "email": "colleengriffith@quintity.com",
    "tags": [
             "consectetur",
             "quis"
    ],
    "profiles": {
      "facebook": {
        "id": 0,
        "picture": "//fbcdn.com/a2244bc1-b10c-4d91-9ce8-184337c6b898.jpg"
      },
      "twitter": {
        "id": 0,
        "picture": "//twcdn.com/ad9e8cd3-3133-423e-8bbf-0602e4048c22.jpg"
      }
    }
  },
      {
    "id": 1,
    "email": "maryellengriffin@ginkle.com",
    "tags": [
             "veniam",
             "elit",
             "mollit"
    ],
    "profiles": {
      "facebook": {
        "id": 1,
        "picture": "//fbcdn.com/12e070e0-21ea-4663-97d0-46bc9c7b67a4.jpg"
      },
      "twitter": {
        "id": 1,
        "picture": "//twcdn.com/3057792f-5dfb-4c4b-86b5-cce4d6bbf7ac.jpg"
      }
    }
  }
]

和我想要的输出:

id,email,tags,profiles.facebook.id,profiles.facebook.picture,profiles.twitter.id,profiles.twitter.picture
0,colleengriffith@quintity.com,"consectetur,quis",0,//fbcdn.com/a2244bc1-b10c-4d91-9ce8-184337c6b898.jpg,0,//twcdn.com/ad9e8cd3-3133-423e-8bbf-0602e4048c22.jpg
1,maryellengriffin@ginkle.com,"veniam,elit,mollit",1,//fbcdn.com/12e070e0-21ea-4663-97d0-46bc9c7b67a4.jpg,1,//twcdn.com/3057792f-5dfb-4c4b-86b5-cce4d6bbf7ac.jpg

这是我到目前为止所做的:

require 'csv'
require 'json'
require 'set'

def get_recursive_keys(hash, nested_key=nil)
  hash.each_with_object([]) do |(k,v),keys|
    k = "#{nested_key}.#{k}" unless nested_key.nil?
      if v.is_a? Hash
      keys.concat(get_recursive_keys(v, k))
    else
      keys << k
    end
  end
end

json = JSON.parse(File.open("live.json").read)
headings = Set.new
json.each do |hash|
  headings.merge(get_recursive_keys(hash))
end

CSV.open('file3.csv', 'w') do |csv|
  csv << headings
  json.each do |hash|
    row = {}
    headings.each do |heading|
      row[heading] = nil
    end
    hash.each do |k,v|
      row[k] = v.to_s.gsub(/\r\n?/, "").delete("\n").delete("\r")
    end
    csv << row.values
  end
end

当我跑步时,我明白了:

id,email,tags,profiles.facebook.id,profiles.facebook.picture,profiles.twitter.id,profiles.twitter.picture
0,colleengriffith@quintity.com,"[""consectetur"", ""quis""]",,,,,"{""facebook""=>{""id""=>0, ""picture""=>""//fbcdn.com/a2244bc1-b10c-4d91-9ce8-184337c6b898.jpg""}, ""twitter""=>{""id""=>0, ""picture""=>""//twcdn.com/ad9e8cd3-3133-423e-8bbf-0602e4048c22.jpg""}}"
1,maryellengriffin@ginkle.com,"[""veniam"", ""elit"", ""mollit""]",,,,,"{""facebook""=>{""id""=>1, ""picture""=>""//fbcdn.com/12e070e0-21ea-4663-97d0-46bc9c7b67a4.jpg""}, ""twitter""=>{""id""=>1, ""picture""=>""//twcdn.com/3057792f-5dfb-4c4b-86b5-cce4d6bbf7ac.jpg""}}"

所以我确实拥有了我需要的一切,但是,我仍然有括号和引号,我想从csv文件中删除它们。

如果有人有想法或提示,那就太好了!

任何帮助表示赞赏,

感谢。

2 个答案:

答案 0 :(得分:1)

我认为你可以使用宝石。这让你的事情更容易。为什么重新发明轮子?。

gem install json2csv

有关详细信息,请参阅here

答案 1 :(得分:1)

Set明确记录为无序,因此您应在填充后立即将标题转换为Array。是的,当前的标准实现是有序的,但最好避免依赖于实现的假设。因此,第一步是确保headings在我们采取任何措施之前保证具有一致的顺序:

headings = headings.to_a
CSV.open('file3.csv', 'w') do |csv|
  ...
end

然后你只需要修复你在进入CSV的过程中如何编码数组和哈希值。您可以使用Hash#dig查找所需的嵌套值,然后修补所有通过简单Array#join调用发出的数组:

json.each do |hash|
  row = headings.map do |h|
    v = hash.dig(*h.split('.'))       # Dig out the (possibly) nested value
    v.is_a?(Array) ? v.join(',') : v  # Fix up arrays
  end
  csv << row
end

我们仍在做一些假设("tags"中没有逗号,JSON键中没有句号,......)当然。

您还可以将标题存储为数组,这样您就不必一直split。然后,您需要在构建标题行时抛出join('.')

add_dots = ->(a) { a.join('.') }
csv << headings.map(&add_dots)

并在构建v时展开数组:

v = hash.dig(*h)

并调整get_recursive_keys以使用数组而不是句点分隔的字符串。