【问题标题】:Transforming the name of key deeper in the JSON structure with jq使用 jq 在 JSON 结构中更深地转换键名
【发布时间】:2015-07-31 23:39:42
【问题描述】:

我有以下 json:

{
  "vertices": [
    {
      "__cp": "foo",
      "__type": "metric",
      "__eid": "foobar",
      "name": "Undertow Metrics~Sessions Created",
      "_id": 45056,
      "_type": "vertex"
    },
    ...
  ]
  "edges": [
  ...

我想实现这种格式:

{
  "nodes": [
    {
      "cp": "foo",
      "type": "metric",
      "label": "metric: Undertow Metrics~Sessions Created",
      "name": "Undertow Metrics~Sessions Created",
      "id": 45056
    },
    ...
  ]
  "edges": [
  ...

到目前为止,我能够创建这个表达式:

jq '{nodes: .vertices} | del(.nodes[]."_type", .nodes[]."__eid")'

即将“顶点”重命名为“节点”并删除“_type”和“__eid”,如何重命名嵌套在 JSON 中更深层次的键?

【问题讨论】:

    标签: json jq


    【解决方案1】:

    如果您使用with_entries(filter),您可以更改对象的属性名称。这会将对象转换为键/值对数组,并对这些对应用过滤器并转换回对象。因此,您只想将这些对象的键更新为您的新名称。

    根据您使用的 jq 版本,下一部分可能会很棘手。直到 jq 1.5 才引入字符串替换。如果可用,您可以这样做:

    {
        nodes: .vertices | map(with_entries(
            .key |= sub("^_+"; "")
        )),
        edges
    }
    

    否则,如果您使用的是 jq 1.4,则必须手动删除它们。递归函数可以帮助解决这个问题,因为下划线的数量会有所不同。

    def ltrimall(str): str as $str |
        if startswith($str)
            then ltrimstr($str) | ltrimall(str)
            else .
        end;
    {
        nodes: .vertices | map(with_entries(
            .key |= ltrimall("_")
        )),
        edges
    }
    

    【讨论】:

      【解决方案2】:

      以下程序适用于 jq 1.4 或 jq 1.5。 它使用 walk/1 从任何键中删除前导下划线,无论它出现在输入 JSON 中的哪个位置。

      此处提供的 ltrim 版本使用 recurse/1 来提高效率和可移植性,但可以使用任何合适的替代品。

      def ltrim(c):
        reduce recurse( if .[0:1] == c then .[1:] else null end) as $x 
          (null; $x);
      
      # Apply f to composite entities recursively, and to atoms
      def walk(f):
       . as $in
       | if type == "object" then
            reduce keys[] as $key
              ( {}; . + { ($key):  ($in[$key] | walk(f)) } ) | f
        elif type == "array" then map( walk(f) ) | f
        else f
        end;
      
      .vertices = .nodes
      | del(.nodes)
      | (.vertices |= walk(
            if type == "object"
            then with_entries( .key |= ltrim("_") )
            else .
            end ))
      

      【讨论】:

        【解决方案3】:

        从您的示例数据看来,您打算进行很多小操作,所以我会将事情分成如下几个阶段:

          .nodes = .vertices                     # \ first take care of renaming
        | del(.vertices)                         # / .vertices to .nodes
        
        | .nodes = [ 
               .nodes[]                          # \ then scan each node
             | . as $n                           # /
        
             | del(._type, .__eid)               # \ whatever key-specific tweaks like 
             | .label = "metric: \(.name)"       # / calculating .label you want can go here
        
             | reduce keys[] as $k (             # \
                 {};                             # | final reduce to handle renaming
                 .[$k | sub("^_+";"")] = $n[$k]  # | any keys that start with _
               )                                 # /
          ]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-05
          • 1970-01-01
          • 1970-01-01
          • 2017-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多