【问题标题】:Relate elements in table form from Json file with jq将 Json 文件中的表格形式的元素与 jq 相关联
【发布时间】:2019-05-30 22:41:10
【问题描述】:

我是 jq 的新手,我有以下代码来获取每个名为 Abc 的元素的列表值:

["Abc"], ( .. | objects | select(has("Abc")) | [.["Abc"]] ) | @tsv

这是我得到的当前输出:

"Abc"
"4"
"2"
"1"
"9"
"3"
"2"
"4"
"9"

我想在左侧添加 4 列,以显示每个 Abc 值对应的页面、行和列。此外,如果可能的话,在第一列添加一个从 1 到“Abc”元素数量的计数器。

下面我显示了当前的输出,与期望的输出和 Json 文件的结构进行了比较,以便澄清:

输入的Json文件如下:

{
  "document": {
    "page": [
      {
        "@index": "0",
        "image": {
          "Abc": "4"
        }
      },
      {
        "@index": "1",
        "row": [
          {
            "column": [
              {
                "text": {
                  "Abc": "2"
                }
              }
            ]
          },
          {
            "column": [
              {
                "text": {
                  "Abc": "1"
                }
              },
              {
                "text": {
                  "Abc": "9"
                }
              }
            ]
          },
          {
            "column": [
              {
                "text": {
                  "Abc": "3"
                }
              }
            ]
          }
        ]
      },
      {
        "@index": "2",
        "row": [
          {
            "column": [
              {
                "text": {
                  "Abc": "2"
                }
              }
            ]
          },
          {
            "column": [
              {
                "text": {
                  "Abc": "4"
                }
              },
              {
                "text": {
                  "Abc": "9"
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

我希望有人可以帮助我。提前致谢。

【问题讨论】:

    标签: json jq tabulate


    【解决方案1】:

    以下解决方案使用paths 并具有几个优点,包括简洁、简单,并且可以轻松适应不同格式的句柄数据。

    为了清楚起见,我们首先定义一个添加行号的函数:

    # add a sequential id, starting at 1
    def tsvRows(s):
      foreach s as $s (0; .+1; [.] + $s)
      | @tsv;
    
    (["counter", "page", "row", "column", "Abc"] | @tsv),
    tsvRows(paths as $p
      | select($p[-1] == "Abc")
      | getpath($p) as $v
      | $p
      | .[2] as $page
      | (if .[3] == "row" then .[4] else null end) as $row
      | (if .[5] == "column" then .[6] else null end) as $column
      | [$page, $row, $column, $v] )
    

    【讨论】:

    • 你说得对,这个解决方案不那么复杂,呵呵。我有一个问题,如果块"text" {} 中有更多元素,例如"text": {"Abc": "4" \n "Def": "5" \n "Ghi": "2"} 如何调整代码以查找更多元素? select($p[-1] == ["Abc", "Def", "Ghi"]) 之类的东西会怎样?
    • 我建议您阅读 jq,如果您无法弄清楚,请务必提出一个单独的具体问题。
    【解决方案2】:

    输入数据的不规则性使得需求有点不透明,但下面会产生所需的输出。

    ["counter", "page", "row", "column", "Abc"],
    (foreach (.document.page[] | objects) as $page ({page: -1, counter: 0};
      .page += 1
      | if ($page | (has("image") and (.image|has("Abc"))))
        then
          .counter +=1
          | .out = [.counter, .page, null, null, ($page|.image.Abc)]
        else foreach ($page | .row[]?) as $row (.row=-1;
          .row += 1
          | foreach ($row | .column[]) as $column (.column=-1;
              .column +=1
              | foreach ($column | .text | objects) as $x (.;
                  .counter += 1
                  | .out = [.counter, .page, .row, .column, $x["Abc"]]
                  ; . )
               ; . )
          ; . )
        end
        ; .out )
    )
    | @tsv
    

    输出

    具体来说,使用 -r 命令行选项,从给定输入生成的输出如下(包括选项卡):

    counter page    row column  Abc
    1   0           4
    2   1   0   0   2
    3   1   1   0   1
    4   1   1   1   9
    5   1   2   0   3
    6   2   0   0   2
    7   2   1   0   4
    8   2   1   1   9
    

    【讨论】:

    • 非常感谢您的帮助。输出是正确的,只有你能帮我在输出中添加元素column 的列,如图所示,这是红色元素
    • column 现在也包含在内。
    • 效果简直太棒了!非常感谢峰。使用|背后的逻辑是什么?我经常在你的代码中看到。当您使用| 将命令的输出传递给另一个命令时,它是否像在 bash 中一样工作?例如ls -1 | sort | uniq
    • 没错,就是用来组成“管道”的“管道”符号。
    猜你喜欢
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 2020-10-21
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 2011-02-19
    相关资源
    最近更新 更多