使用jq或bash中的任何其他工具比较两个json文件

时间:2017-10-17 10:59:46

标签: json bash jq containment elaboration

我想比较两个json文件,看看是否可以从另一个中提取一个
P1(p1.json)

{
  "id": 12,
  "keys": ["key1","key2"],
  "body": {
    "height": "180cm",
    "wight": "70kg"
  },
  "name": "Alex"
}

P2(p2.json)

{
  "id": 12,
  "keys": ["key2","key1"],
  "body": {
    "height": "180cm"
  }
}

可以看出 P2 并不完全等于 P1 ,但可以从 P1 中提取(它提供的数据较少同一个人,但数据是正确的)。

预期行为:

p1 extends p2 --> true
p2 extends p1 --> false


备注
- 无法使用一些其他元素从同一数组中提取数组

2 个答案:

答案 0 :(得分:2)

extends/1的以下定义使用纯粹基于对象的扩展定义(特别是,它不对数组进行排序)。关于数组的OP要求对我来说不清楚,但在下一节中提供了变体定义。

# Usage: $in | extends($b) iff $in contains $b in an object-based sense
def extends($b):
  # Handle the case that both are objects:
  def objextends($x):
    . as $in | all($x|keys[]; . as $k | $in[$k] | extends($x[$k]));
  # Handle the case that both are arrays:
  def arrayextends($x):
    . as $in
    | length == ($x|length) and
        all( range(0;length); . as $i | $in[$i] | extends($x[$i]));

  if . == $b then true
  else . as $in
  | type as $intype
  | ($intype == ($b|type)) and
      (($intype == "object" and objextends($b)) or
       ($intype == "array" and arrayextends($b)))

端;

示例:

{a:{a:1,b:2}, b:2} | extends({a:{a:1}}) # true

{a:{a:1,b:2}, b:2} | extends({a:{a:2}}) # false

{a:{a:1,b:2}, b:[{x:1,y:2}]} | extends({a:{a:2}, b:[{x:1}]}) # true

替代定义

以下定义对数组进行排序,并且足以处理给定的示例:

# Usage: $in | extends2($b) iff $in contains $b in a way which ignores the order of array elements
def extends2($b):
  # Both are objects
  def objextends($x):
    . as $in | all($x|keys[]; . as $k | $in[$k] | extends($x[$k]));

  def arrayextends($x): ($x|sort) - sort == [];

  if . == $b then true
  else . as $in
  | type as $intype
  | ($intype == ($b|type)) and
      (($intype == "object" and objextends($b)) or
       ($intype == "array"  and arrayextends($b)))
  end;

显示$ P1和$ P2:

  $P1 | extends2($P2) # yields true

答案 1 :(得分:0)

如果您知道任何子阵列中没有重复项,那么您可以使用此方法计算从tostream返回的[path,value]对的集合之间的差异,用null替换数组索引:< / p>

def details:[
     tostream
   | select(length==2) as [$p,$v]
   | [$p|map(if type=="number" then null else . end),$v]
];

def extends(a;b): (b|details) - (a|details) == [];

如果P1P2是返回样本数据的函数

def P1: {
    "id": 12,
    "keys": ["key1","key2"],
    "body": {
      "height": "180cm",
      "wight": "70kg"
    },
    "name": "Alex"
  }
;

def P2: {
    "id": 12,
    "keys": ["key2","key1"],
    "body": {
      "height": "180cm"
    }
  }
;

然后

  extends(P1;P2)  # returns true
, extends(P2;P1)  # returns false

在存在重复的情况下,结果不太清楚。 e.g。

  extends(["a","b","b"];["a","a","b"])  # returns true

Try it online!