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

时间:2015-07-31 23:39:42

标签: json jq

我跟随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中更深的密钥?

3 个答案:

答案 0 :(得分:2)

如果使用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
}

答案 1 :(得分:1)

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

答案 2 :(得分:1)

从您的示例数据看起来您打算进行大量的操作,因此我会将事情分解为以下几个阶段:

  .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 _
       )                                 # /
  ]
相关问题