【问题标题】:How to tabulate nested JSON file with jq如何用 jq 将嵌套的 JSON 文件制表
【发布时间】:2019-06-05 21:58:45
【问题描述】:

我有以下 JSON 文件,我想用有人建议我的 jq 工具解析它,但我是新手。有3个父节点 有相同的孩子名字。父节点是 MNR、GNR 和 MSNR,每个节点都有名为 N1、N2、NR_i、NR_f 的子节点。

{
  "Main": {
    "Document": "Doc.1",
    "Cini": "DDFR",
    "List": {
      "SubList": {
        "CdTa": "ABC",
        "NN": "XYZ",
        "ND": {
          "RiS": {
            "RiN": {
              "NSE14": {
                "MNRs": {
                  "MRD": [
                    {
                      "NR": {
                        "N1": "393",
                        "N2": "720",
                        "SNR": {
                          "NR_i": "203",
                          "NR_f": "49994"
                        }
                      }
                    },
                    {
                      "NR": {
                        "N1": "687",
                        "N2": "345",
                        "SNR": {
                          "NR_i": "55005",
                          "NR_f": "1229996"
                        }
                      }
                    }
                  ]
                },
                "GNRs": {
                  "RD": {
                    "NR": {
                      "N1": "649",
                      "N2": "111",
                      "SNR": {
                        "NR_i": "55400",
                        "NR_f": "877"
                      }
                    }
                  }
                },
                "MSNRs": {
                  "NR": [
                    {
                      "N1": "748",
                      "N2": "5624",
                      "SNR": {
                        "NR_i": "8746",
                        "NR_f": "7773"
                      }
                    },
                    {
                      "N1": "124",
                      "N2": "54",
                      "SNR": {
                        "NR_i": "8847",
                        "NR_f": "5526"
                      }
                    }
                  ]
                }
              },
              "NSE12": {
                "MBB": "990",
                "MRB": "123"
              },
              "MGE13": {
                "TBB": "849",
                "TRB": "113"
              }
            }
          }
        }
      }
    }
  }
}

使用此代码,我得到以下内容

.Main.List.SubList.ND.RiS.RiN.NSE14.MNRs.MRD

[
  {
    "NR": {
      "N1": "393",
      "N2": "720",
      "SNR": {
        "NR_i": "203",
        "NR_f": "49994"
      }
    }
  },
  {
    "NR": {
      "N1": "687",
      "N2": "345",
      "SNR": {
        "NR_i": "55005",
        "NR_f": "1229996"
      }
    }
  }
]

通过这些命令,我​​得到了每个孩子的单独值的列,而其他的则为空。

.. | .N1?
.. | .N2?
.. | .NR_i?
.. | .NR_f?

我离我想要的输出还很远,因为我想为每个父母提取孩子并在 如下表格。

+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
|             MNRs              |          GNRs            |           MSNRs          |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| N1   | N2   | NR_i  | NR_f    | N1  | N2  | NR_i  | NR_f | N1  | N2   | NR_i | NR_f |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| 393  | 720  | 203   | 49994   | 649 | 111 | 55400 | 877  | 748 | 5624 | 8746 | 7773 |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+
| 687  | 345  | 55005 | 1229996 |     |     |       |      | 124 | 54   | 8847 | 5526 |
+------+------+-------+---------+-----+-----+-------+------+-----+------+------+------+ 

请有人帮我解决这个问题。提前致谢。

【问题讨论】:

    标签: json parsing jq reformatting


    【解决方案1】:

    由于输入 JSON 的性质仅通过示例给出,让我们首先定义一个用于线性化 .NR 的过滤器:

    # Produce a stream of arrays
    def linearize:
      if type == "array" then .[] | linearize
      else [ .N1, .N2, .SNR.NR_i, .SNR.NR_f]
      end;
    

    现在可以在保留顶级组的同时提取相关数据,如下所示:

    .Main.List.SubList.ND.RiS.RiN.NSE14
    | [to_entries[]
    | [.key]
      + [.value | .. | objects | select(has("NR")) | .NR | [ linearize ]] ]
    

    由于输入的 JSON 不是统一的,因此通过使用以下映射扩充上述管道将有助于确保统一:

    | map(if length > 2 then [.[0], [.[1:][][]]] else . end)
    

    这会生成一个结构如下的 JSON 数组:

    [["MNRs",[["393","720","203","49994"]],[["687","345","55005","1229996"]]],
     ["GNRs", ...
    

    为了从这个中间结果中获得表的第一行数据,定义一个提供必要填充的函数是值得的:

    def row($i; $padding):
      . as $in
      | [range(0;$padding) | null] as $nulls
      | reduce range(0; length) as $ix 
          ([]; . + ($in[$ix][1][$i] // $nulls));
    

    现在可以通过row(0;4)获取第一个数据行,通过row(1;4)获取第二个数据,以此类推

    数据行总数将通过map(.[1] | length) | max过滤中间数据结构得到;因此,可以通过在前面的管道上添加以下内容来获取数据行:

    | (map(.[1] | length) | max) as $rows
    | range(0; $rows) as $r
    | row($r; 4)
    | @tsv
    

    使用 -r 命令行选项和给定的示例,输出将是:

    393 720 203 49994   649 111 55400   877 748 5624    8746    7773
    687 345 55005   1229996                 124 54  8847    5526
    

    添加标题作为练习:-)

    【讨论】:

    • 太棒了。我刚刚比过去 10 个小时的 tuts 和 man 了解了更多关于 jq 的信息
    • @peak 非常感谢您的大力支持。我必须说我不太了解您使用的先进技术。您能否建议我一些带有 jq 或 jq 网站本身的教程和示例的好网站?关于代码仅在 row 函数定义之前对我有用。我在这里试过https://jqplay.org/s/aUTncmciuj
    • @GerCas - 您必须将 all 的 defs 放在 all 主管道之前。不应有“|”紧跟在 defs 部分之后。
    • @Cergas - 关于学习资源,请参阅我在stackoverflow.com/questions/56435383 的回复中的“资源”部分,以及之后的第一条评论。
    • @peak 非常感谢您的更正。现在它完美无缺。我试图添加标题,认为将粘贴在 Excel 中,这是合并的 4 个单元格中的每个标题。我试过这个["MNRs","\t\t\t","GNRs","\t\t\t","MSNRs","\t\t\t"],,但输出很糟糕。但这是一个小问题。关于学习资源,我不知道 Rossetacode 网站。这很棒。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-28
    • 1970-01-01
    相关资源
    最近更新 更多