PHP - 比较两个 JSON 对象的结构

Posted

技术标签:

【中文标题】PHP - 比较两个 JSON 对象的结构【英文标题】:PHP - compare the structure of two JSON objects 【发布时间】:2015-11-09 19:33:51 【问题描述】:

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

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

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


    "index": 0,
    "tags": [
        "abc"
    ]


    "index": 1,
    "tags": [
        "xyz"
    ]

想法?

【问题讨论】:

所以您想检查对象 1 是否与对象 2 具有相同的字段? 是的,完全正确。我尝试使用 RecursiveArrayIterator::hasChildren() 来仅迭代叶子,但在我看来这个解决方案并不优雅。可能有人知道更好的方法吗? @Boarking,你搞定了吗? 也许有用? compare object properties and show diff in php 【参考方案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 ";
    



?>

【讨论】:

以上是关于PHP - 比较两个 JSON 对象的结构的主要内容,如果未能解决你的问题,请参考以下文章

PHP JSON数组与对象的理解

PHP JSON数组与对象的理解

获取json对象的长度

使用 php mysql 创建嵌套的 json 对象

json数据结构和gson的比较

利用PHP脚本辅助MySQL数据库管理4-两个库表结构差异比较