使用jq重新组织对象字段

3

我想知道是否有一种方法可以使用jq重新组织对象的字段。

我的意思是,假设

{
  "prop1": 1,
  "prop2": {
    "nested": 0
  },
  "prop3": true
}

我想获取这个

{
  "prop1": 1,
  "prop3": true,
  "prop2": {
    "nested": 0
  }
}

我想要选择字段的顺序(不考虑字段类型或字母顺序,只根据我的选择 :))。
谢谢!

2
你为什么要在意呢?这是一个字典,根据定义它是无序的,你总是可以通过键找到对应的值。 - favoretti
文件随后由某个程序处理,该程序不知道它是json格式(也不需要知道),因此顺序很重要。 - ValLeNain
虽然从技术上讲是可能的,但我强烈建议不要使用不理解JSON的程序来处理JSON。 - user3899165
是的,但有时您必须 git diff JSON 文件 :) - ValLeNain
你可以将JSON文件输入Python,键将被排序:python -mjson.tool file_name。非常简单。 - Jason Hu
4个回答

3

[以下是2015年8月发布答案的更新内容!]

对于 jq 版本1.4及以上的版本,显式指定键的顺序最简单的方法是使用

{foo,bar,...}

来指定对象。例如,如果输入文件 input.json 中有问题中显示的 JSON,则可以执行以下操作:

jq -Mc '{prop1, prop3, prop2}' input.json

生成:

{"prop1":1,"prop3":true,"prop2":{"nested":0}}

在这种情况下,仅受到顶级键的排序影响。
原始问题指出需要规范化JSON以便使用面向文本的diff。为此,通常需要规范化对象,无论嵌套多深。为此,jq(1.4及以上版本)具有-S命令行选项。
以下是上述“中序”的变体。所需的JSON对象(而不是字符串化版本)直接构造。由于默认情况下按创建顺序有效地存储键,因此可以在jq 1.4及更高版本中使用该方法。
def orderKeys(keys):
  . as $in
  | reduce keys[] as $key ({}; . + { ($key): $in[$key] });

# Example:
orderKeys( ["prop1", "prop3", "prop2"] )

将上述内容保存在名为order-keys.jq的文件中,并使用任务描述中的JSON作为输入,运行以下命令:

$ jq -M -n -c -f order-keys.jq

产生:

{"prop1":1,"prop3":true,"prop2":{"nested":0}}

谢谢您。您是否看到一种默认情况下未命名键的属性包含方式? - Manuel Fahndrich
@ManuelFahndrich - 请查看使用“对象减法”的单独答案。 - peak

0

好的,回答我的后续问题。这是我自己的hacky解决方案,将“剩余”的属性(未在顺序中指定)包含在结果对象的末尾,以便不会丢失任何输入:

def orderKeys(orderedkeys):
  . as $in
  | reduce keys[] as $key ({}; if orderedkeys|contains([$key]) then . else . + { ($key): $in[$key] } end)
  | . as $rest
  | reduce orderedkeys[] as $key ({}; . + { ($key): $in[$key] })
  | . + $rest;

# Example:
orderKeys( ["prop1", "prop3", "prop2"] )

在输入上

{
  "prop1": 1,
  "otherprop": "foo",
  "prop2": {
    "nested": 0
  },
  "prop3": true
}

这将产生

{
  "prop1": 1,
  "prop3": true,
  "prop2": {
    "nested": 0
  },
  "otherprop": "foo"
}

0
在后续的问题中,@ManuelFahndrich问道:
“您是否看到一种默认情况下未命名键包含属性的方法?”
这里有一个简单的方法,使用to_entriesfrom_entries执行“对象减法”:
{prop1, prop3, prop2} as $first
| $first + (to_entries - ($first|to_entries) | from_entries)

0

你唯一安全的选择是手动生成 JSON 字符串,并按照你想要的顺序排列属性。不能保证对象上设置属性的顺序会被保留。

你可以使用以下函数来实现:

def inorder(names): names as $names | . as $obj
    | "{\($names | map("\(@json):\($obj[.])") | join(","))}"
    ;

接着使用它:

inorder(["prop1", "prop3", "prop2"])

请记住,这将返回一个字符串。您需要获取原始输出以将其作为对象返回。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接