使用jq在JSON结构中更深层地转换键的名称

使用jq在JSON结构中更深层地转换键的名称,json,jq,Json,Jq,我有以下建议: { "vertices": [ { "__cp": "foo", "__type": "metric", "__eid": "foobar", "name": "Undertow Metrics~Sessions Created", "_id": 45056, "_type": "vertex" }, ... ] "edges": [ ... 我希望实现这种格式: {

我有以下建议:

{
  "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")'

例如,将“顶点”重命名为“节点”并删除“\u type”和“\u eid”,如何重命名JSON中嵌套得更深的键?

如果与\u entriesfilter一起使用,可以更改对象属性的名称。这会将对象转换为键/值对数组,并对键/值对应用筛选器,然后再转换回对象。因此,您只需要将这些对象的键更新为新名称

根据您使用的jq版本,下一部分可能会比较棘手。直到JQ1.5才引入字符串替换。如果可用,您可以执行以下操作:

{
    nodes: .vertices | map(with_entries(
        .key |= sub("^_+"; "")
    )),
    edges
}
否则,如果您使用的是JQ1.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
}

如果与_entriesfilter一起使用,则可以更改对象特性的名称。这会将对象转换为键/值对数组,并对键/值对应用筛选器,然后再转换回对象。因此,您只需要将这些对象的键更新为新名称

根据您使用的jq版本,下一部分可能会比较棘手。直到JQ1.5才引入字符串替换。如果可用,您可以执行以下操作:

{
    nodes: .vertices | map(with_entries(
        .key |= sub("^_+"; "")
    )),
    edges
}
否则,如果您使用的是JQ1.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
}

以下程序适用于JQ1.4或JQ1.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 ))

以下程序适用于JQ1.4或JQ1.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 ))

从您的示例数据来看,您似乎打算进行许多小操作,因此我将把事情分为以下几个阶段:

  .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 _
       )                                 # /
  ]

从您的示例数据来看,您似乎打算进行许多小操作,因此我将把事情分为以下几个阶段:

  .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 _
       )                                 # /
  ]