You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Karate实现带主键的大规模JSON文件差异对比方案问询

问题

我有两个需对比的大规模JSON文件(示例如下),需求如下:

  • 以S_Object_ID为主键,按条目单独获取差异;
  • 忽略条目顺序,得到对比结果;
  • 验证子条目块的主键Sequence_Number;
  • 找出两个文件中各自缺失的条目。

请问在Karate中实现该需求的最优方式是什么?

JSON FILE-1

{
    "Items": [
        {
            "Delivery_Item": "Y",
            "S_Object_ID": "1002",
            "Sweetener_Group": "N/A",
            "DMB_Item": "N"
        },
        {
            "Delivery_Item": "Y",
            "S_Object_ID": "1007",
            "Sweetener_Group": "N/A",
            "DMB_Item": "N"
        },
        {
            "Delivery_Item": "Y",
            "S_Object_ID": "101000001",
            "Sweetener_Group": [
                {
                    "Min_Qty": "0",
                    "Pricing_Level": "N/A",
                    "Sequence_Number": "1",
                    "LTO": "-",
                    "Default_Quantity_XL": "N/A",
                    "Group": "Sweetener_1",
                    "Default_Quantity_L": "N/A",
                    "S_Object_Item_ID": "-",
                    "Max_Qty": "1",
                    "Regional": "N/A"
                },
                {
                    "Min_Qty": "0",
                    "Pricing_Level": "N/A",
                    "Sequence_Number": "2",
                    "LTO": "-",
                    "Default_Quantity_XL": "5",
                    "Group": "Sweetener_1",
                    "Default_Quantity_L": "4",
                    "S_Object_Item_ID": "102003004",
                    "Max_Qty": "10",
                    "Regional": "5"
                }
            ],
            "DMB_Item": "N"
        }

    ],
    "Count": 3
}

JSON FILE-2

{
    "Items": [
        {
            "Delivery_Item": "N",
            "S_Object_ID": "1007",
            "Sweetener_Group": "N/A",
            "DMB_Item": "N"
        },
                {
            "Delivery_Item": "Y",
            "S_Object_ID": "1002",
            "Sweetener_Group": "N/A",
            "DMB_Item": "N"
        },
        {
            "Delivery_Item": "Y",
            "S_Object_ID": "101000001",
            "Sweetener_Group": [
                {
                    "Min_Qty": "5",
                    "Pricing_Level": "N/A",
                    "Sequence_Number": "1",
                    "LTO": "-",
                    "Default_Quantity_XL": "N/A",
                    "Group": "Sweetener_1",
                    "Default_Quantity_L": "N/A",
                    "S_Object_Item_ID": "-",
                    "Max_Qty": "1",
                    "Regional": "N/A"
                }
            ],
            "DMB_Item": "N"
        },
        {
            "Delivery_Item": "Y",
            "S_Object_ID": "101000002",
            "Sweetener_Group": "N/A",
            "DMB_Item": "N"
        }   

    ],
    "Count": 4
}
解决方案

Karate的核心特性(match断言、JSON转换、集合操作)可以完美覆盖这些需求,以下是最优实现步骤:

1. 加载文件并转换为键值映射

先把两个文件的Items数组转成以S_Object_ID为键的Map,直接忽略条目顺序,按主键快速定位条目:

* def file1 = read('file1.json')
* def file2 = read('file2.json')
* def map1 = karate.mapWithKey(file1.Items, 'S_Object_ID')
* def map2 = karate.mapWithKey(file2.Items, 'S_Object_ID')

2. 找出双方缺失的条目

提取两个Map的主键集合,对比得到各自缺失的条目ID:

* def keys1 = karate.keysOf(map1)
* def keys2 = karate.keysOf(map2)
* def missingInFile1 = karate.filter(keys2, function(x){ return !(x in map1) })
* def missingInFile2 = karate.filter(keys1, function(x){ return !(x in map2) })
* print 'File1缺失的条目ID:', missingInFile1
* print 'File2缺失的条目ID:', missingInFile2

3. 按主键对比条目差异

遍历共同主键,逐一对比顶层字段和子数组Sweetener_Group的差异:

* def commonKeys = karate.filter(keys1, function(x){ return x in map2 })
* def diffs = []
* karate.forEach(commonKeys, function(key){
    * def item1 = map1[key]
    * def item2 = map2[key]
    * def diff = { S_Object_ID: key }
    // 对比顶层字段
    * if (item1.Delivery_Item != item2.Delivery_Item) diff.Delivery_Item = [item1.Delivery_Item, item2.Delivery_Item]
    * if (item1.DMB_Item != item2.DMB_Item) diff.DMB_Item = [item1.DMB_Item, item2.DMB_Item]
    // 处理Sweetener_Group的对比
    * def sg1 = item1.Sweetener_Group
    * def sg2 = item2.Sweetener_Group
    * if (sg1 != sg2) {
        * if (sg1 == 'N/A' || sg2 == 'N/A') {
            * diff.Sweetener_Group = [sg1, sg2]
        } else {
            // 子数组按Sequence_Number转Map后对比
            * def sgMap1 = karate.mapWithKey(sg1, 'Sequence_Number')
            * def sgMap2 = karate.mapWithKey(sg2, 'Sequence_Number')
            * def sgDiff = {}
            // 子数组缺失的Sequence_Number
            * def sgKeys1 = karate.keysOf(sgMap1)
            * def sgKeys2 = karate.keysOf(sgMap2)
            * def sgMissingInFile1 = karate.filter(sgKeys2, function(x){ return !(x in sgMap1) })
            * def sgMissingInFile2 = karate.filter(sgKeys1, function(x){ return !(x in sgMap2) })
            * if (sgMissingInFile1.length > 0) sgDiff.missingInFile1 = sgMissingInFile1
            * if (sgMissingInFile2.length > 0) sgDiff.missingInFile2 = sgMissingInFile2
            // 子数组字段差异
            * def sgCommonKeys = karate.filter(sgKeys1, function(x){ return x in sgMap2 })
            * karate.forEach(sgCommonKeys, function(sgKey){
                * def sgItem1 = sgMap1[sgKey]
                * def sgItem2 = sgMap2[sgKey]
                * def sgItemDiff = {}
                * karate.forEach(karate.keysOf(sgItem1), function(field){
                    * if (sgItem1[field] != sgItem2[field]) sgItemDiff[field] = [sgItem1[field], sgItem2[field]]
                })
                * if (!karate.isEmpty(sgItemDiff)) sgDiff[sgKey] = sgItemDiff
            })
            * if (!karate.isEmpty(sgDiff)) diff.Sweetener_Group = sgDiff
        }
    }
    * if (!karate.isEmpty(diff)) karate.appendTo(diffs, diff)
})
* print '条目差异详情:', diffs

4. 验证子条目Sequence_Number规则

如果需要校验Sweetener_Group的Sequence_Number是否连续递增,可单独编写验证逻辑:

* def validateSequence = function(items){
    * karate.forEach(items, function(item){
        * def sg = item.Sweetener_Group
        * if (sg != 'N/A') {
            * def sequences = sg.map(function(x){ return parseInt(x.Sequence_Number) })
            * sequences.sort()
            * karate.forEach(sequences, function(num, index){
                * assert num == index + 1
            })
        }
    })
}
* validateSequence(file1.Items)
* validateSequence(file2.Items)

5. 断言结果(可选)

如果是测试场景,可直接对对比结果做断言验证:

// 断言File1缺失的条目是101000002
* assert missingInFile1 == ['101000002']
// 断言差异列表包含预期条目
* assert diffs.length == 2
* assert diffs[0].S_Object_ID == '1007'
* assert diffs[0].Delivery_Item == ['Y', 'N']

内容的提问来源于stack exchange,提问作者Sumith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:45:39