【问题标题】:PHP - compare the structure of two JSON objectsPHP - 比较两个 JSON 对象的结构
【发布时间】:2023-03-26 17:50:01
【问题描述】:

我有两个 JSON 对象,我想比较它们的结构。我该怎么做?

这些对象是即时生成的,取决于动态内容。 这意味着对象总是不同,但大多数时候具有相同的结构。我希望能够在更改发生后及时发现

示例:这两个对象应该被视为相等,因为它们具有相同的结构:索引变量和标签数组。

{
    "index": 0,
    "tags": [
        "abc"
    ]
}
{
    "index": 1,
    "tags": [
        "xyz"
    ]
}

想法?

【问题讨论】:

  • 所以您想检查对象 1 是否与对象 2 具有相同的字段?
  • 是的,完全正确。我尝试使用 RecursiveArrayIterator::hasChildren() 来仅迭代叶子,但在我看来这个解决方案并不优雅。可能有人知道更好的方法吗?
  • @Boarking,你搞定了吗?

标签: php json object


【解决方案1】:

##你可以使用这个库TreeWalkerphp .##

TreeWalker 是 php 中一个简单而小型的 API
(我开发了这个库,希望对你有帮助)

它提供了两种方法
1- 获取 json 差异
2- 编辑 json 值(递归)

此方法将返回 json1 和 json2 之间的差异

$struct1 = array("casa"=>1, "b"=>"5", "cafeina"=>array("ss"=>"ddd"), "oi"=>5);
$struct2 = array("casa"=>2, "cafeina"=>array("ss"=>"dddd"), "oi2"=>5);

//P.s
print_r($treeWalker->getdiff($struct1, $struct2))

{
    new: {
        b: "5",
        oi: 5
    },
    removed: {
        oi2: 5
    },
    edited: {
        casa: {
          oldvalue: 2,
          newvalue: 1
        },
        cafeina/ss: {
          oldvalue: "dddd",
          newvalue: "ddd"
        }
    },
    time: 0
}

【讨论】:

  • 我在我当前的工作项目中使用了这个库 - 非常适合我的目的(需要一个差异)。两个竖起大拇指
  • 我也刚用过这个包,效果很好。为我节省了很多时间,谢谢!
【解决方案2】:

有点粗糙,但你懂的;

$json = '[
        {
            "index": 0,
            "tags": [
                "abc"
            ]
        },
        {
            "index": 1,
            "tags": [
                "xyz"
            ]
        },
        {
            "foo": 2,
            "bar": [
                "xyz"
            ]
        }]';

$array = json_decode($json, true);
$default = array_keys($array[0]);

$error = false;
$errors = array();
foreach ($array as $index => $result):
    foreach ($default as $search):
        if (!isset($result[$search])):
            $error = true;
            $errors[] = "Property '{$search}' at entry '{$index}' not found. ";
        endif;
    endforeach;
endforeach;

if ($error):
    echo 'Objects are not the same. ';
    foreach ($errors as $message):
        echo $message;
    endforeach;
endif;

返回:

对象不一样。未找到条目“2”处的属性“索引”。未找到条目“2”处的属性“标签”。

【讨论】:

  • 这里的问题在于默认数组。我怎样才能生成它?我只有两个 JSON 对象。 array_keys() 也不是一个好的选择,因为它不是递归的。我的实际对象非常大,并且有很多级别的嵌套。我必须能够比较一切。
  • 不能期待某种结构吗?据我所知,要有效地做到这一点,您需要有所期待。
  • 我不知道我在期待什么。我所知道的是我有两个可能相同的 JSON 对象,但在继续之前我必须确定。
【解决方案3】:

你的意思是结构,比如模型数组:

array ( 'index' => int, 'tags' =>  array() )

如果这就是你想要得到的,试试这个......

$arr1 = array (
    array (
        'index' => 0,
        'tags' =>  ['abc']
    ),
    array (
        'index' => 1,
        'tags' =>  ['xyz']
    ),
    array (
        'index' => 2,
        'tags' =>  ['xyz'],
        'boom' =>  'granade'
    ),
    array (
        'index' => 3,
        'tags' =>  'xyz'
    )
);

$holder = array();

$model  = array ('index' => 0, 'tags' => array());

for ($i = 0;$i < count($arr1); $i++)
{
    $holder = array_diff(array_merge_recursive($arr1[$i], $model), $model);

    if (!empty($holder))
    {
        echo "different structure<br>";
    }
    else
    {
        echo "same structure<br>";

        // for further validation
        /*
        $keys = array_keys($model);

        if (is_int($arr1[$i][$keys[0]]) && is_array($arr1[$i][$keys[1]]))
            echo "same structure<br>";
        else
            echo "different structure<br>";
        */
    }

}

样本输出:

same structure
same structure
different structure
different structure

【讨论】:

    【解决方案4】:

    你可以尝试使用包https://github.com/coduo/php-matcher

    示例:这两个对象应该被认为是相等的,因为它们具有相同的结构:索引变量和标签数组。

    您可以像这样创建“php-matcher 模式”:

    {
        "index": "@integer@",
        "tags": "@array@.repeat(\"@string@\")"
    }
    

    然后你将你的 JSON 与这个模式进行匹配。如果您有 2 个 JSON 并且都匹配此模式,那么根据您上面对相等的定义,这意味着它们是 “相等”

    请在“php-matcher 沙箱”中查看您提供的示例 JSON 的结果:

    Example 1 in sandbox

    Example 2 in sandbox

    此外,当模式与值不匹配时,您可以使用包 https://github.com/sebastianbergmann/diff(如果您有 phpunit,您应该已经拥有)生成差异。

    例如:

    use SebastianBergmann\Diff\Differ;
    use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
    
    ...
        $valueToCheck = '{
            "foo": 0,
            "bar": {"one": 1, "two": "2"}
        }';
        $expectedValuePattern = '{
            "foo": "@integer@",
            "bar": {"one": 1, "two": 2}
        }';
    
        if (!$matcher->match($valueToCheck, $expectedValuePattern)) {
            $differ = new Differ(
                new UnifiedDiffOutputBuilder(
                    "Json value is not matching expected format:\n",
                    true
                )
            );
            $diffOutput = $differ->diff(
                \json_encode(\json_decode($expectedValuePattern, true), JSON_PRETTY_PRINT),
                \json_encode(\json_decode($valueToCheck, true), JSON_PRETTY_PRINT)
            );
    
            var_dump(
                $diffOutput
                . "\n".$matcher->getError()."\n"
            );
        } else {
            var_dump('OK');
        }
    

    它会打印出来:

    Json value is not matching expected format:
    @@ -1,7 +1,7 @@
     {
    -    "foo": "@integer@",
    +    "foo": 0,
         "bar": {
             "one": 1,
    -        "two": 2
    +        "two": "2"
         }
     }
    
    

    带有 diff 的消息特别有助于较大的 JSON 快速查看哪个元素不匹配。

    在该软件包的 README 中查看更多使用方式 - 特别是:

    https://github.com/coduo/php-matcher#json-matching

    https://github.com/coduo/php-matcher#json-matching-with-unbounded-arrays-and-objects

    这个包非常适合用于自动测试(例如:phpunit)来断言来自 API 响应的 JSON 是否正确等 - 考虑到在集成测试中通常有许多 id、uuid、datetime 等在每个测试中都会发生变化执行 - 如数据库生成的 id 等。

    希望对你有帮助:)

    【讨论】:

      【解决方案5】:

      您可以将json字符串转换为php数组,然后使用array_diff($arr1,$arr2)函数将新创建的数组与另一个数组进行比较 结果是一个数组,其中包含第一个数组中不存在于另一个数组中的元素

      例子:

      <?php 
          $array1 = '{"name":"myname","age":"40"}';
          //convert the obtained stdclass object to an array
          $array1 = (array) json_decode($array1); 
      
      
      
          $array2 = array("name"=>"myname123","age"=>10);
      
          print_r($array2);
      
          $result_array = array_diff($array1,$array2);
      
      
          if(empty($result_array[0])){     
              echo "they have the same structure ";
          }
      
      
      
      ?>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-02
        • 1970-01-01
        • 2013-05-25
        • 2016-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多