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 对象的结构的主要内容,如果未能解决你的问题,请参考以下文章