【问题标题】:How to save the tree structure when parsing json?解析json时如何保存树形结构?
【发布时间】:2018-10-02 07:26:31
【问题描述】:

我的json:

{
    "catalogs": {
        "name": "catalog 1C",
        "children": [{
                "name": "Philips",
                "children": {}
            },
            {
                "name": "BenQ",
                "children": [{
                    "name": "Monitor",
                    "children": [{
                        "name": "19 inches",
                        "children": [{"name": "IPS", "children": {}}, 
                                     {"name": "TFT","children": {}}] 
                     },
                     {
                         "name": "24 inches",
                         "children": {} }]
                }]
            }
        ]
    }
}

Json 相互之间具有相同的键和嵌套级别。
сhildren 可以有多个目录(例如 IPSTFT )。

这是一个菜单,其中一些项目应位于同一级别。我用宝石ancestry

我写了一个递归函数(在控制器中):

def call
  # file - inside the json to parse
  data_hash = JSON.parse(file)

  data_hash["catalogs"]["children"].each do |k|
    ancestry = Category.create_with(name: k["name"]).find_or_create_by!(uid_catalog: k["uid_catalog"])

    if k["children"].present?
      k["children"].each do |parent|
        parent["children"].each do |child|
          walk_tree(child, ancestry)
        end
      end
    end
  end
end

def walk_tree(root, ancestry)
  ancestry = ancestry.children.find_or_create_by!(name: root["name"])

  root["children"].each do |child|
    ancestry = ancestry.children.find_or_create_by!(name: child["name"])
    walk_tree(child["children"], ancestry) if child["children"].present?
  end
end

目前函数输出:

  - BenQ
    - 19 inches
      - IPS
        - TFT

我想要这样(缺一级Monitor):

  - BenQ
    - Monitor
       - 19 inches
         - IPS
         - TFT
       - 24 inches 

【问题讨论】:

  • 请提供load_categories的完整代码。目前尚不清楚ancestry 属性从何而来。
  • done) 稍作修改,但逻辑是一样的
  • 谢谢,这样更好

标签: ruby-on-rails json ruby


【解决方案1】:

快速调试后发现问题的原因。看看这段代码。请注意我的 cmets:

data_hash["catalogs"]["children"].each do |k|
  # k == { "name": "BenQ", "children": [...] }
  ancestry = Category.create_with(name: k["name"]).
    find_or_create_by!(uid_catalog: k["uid_catalog"])

  if k["children"].present?
    k["children"].each do |parent|
      # parent == { "name": "Monitor", "children": [...] }
      parent["children"].each do |child|
        # child == { "name": "19 inches", "children": [...] }
        walk_tree(child, ancestry)
      end
    end
  end
end

因此您不会将parent 作为单独的节点处理;相反,您的代码会立即深入到parent["children"]。这就是缺少一层嵌套的原因。

我认为您需要删除内部迭代器,并将其重写为:

data_hash["catalogs"]["children"].each do |k|
  ancestry = Category.create_with(name: k["name"]).
    find_or_create_by!(uid_catalog: k["uid_catalog"])

  if k["children"].present?
    k["children"].each do |child|
      walk_tree(child, ancestry)
    end
  end
end

【讨论】:

  • 现在有一个问题:walk_tree 中没有哈希 - {},而是数组 - [{"name"=>"IPS", "children"=>[{}]}, {"name"=>"TFT", "children"=>[{}]}]。结果,错误 - TypeError - no implicit conversion of String into Integer
  • 不确定是什么问题。添加code guardif root["children"].present? ...能解决问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多