مقارنة كائنات JSON وكشف المفاتيح المتغيرة
ضع النسخة القديمة والجديدة من سجل بيانات جنبًا إلى جنب واحصل على الاختلافات الحقيقية فقط: في المثال إضافتان وحذف واحد وتغييران، 5 في المجموع، دون احتساب المسافات أو ترتيب المفاتيح. مجاني في متصفحك.
- مجاني
- يعمل في متصفحك
- دون تسجيل
- بياناتك لا تغادر جهازك
شغّل الأداة مجانًا
تعمل هذه الأداة داخل متصفحك — مجانًا، ولا تُرسل بياناتك إلى أي خادم
تحتفظ المصفوفات بترتيبها وتُقارن كوحدة كاملة. العملية حتمية ولا تستخدم الشبكة، وترفض المصفوفات والقيم الأولية وnull في المستوى الأعلى.
مقارنة البيانات لا النص
تجعل مقارنة النصوص تحديثًا صغيرًا يبدو ضخمًا، لأن الإزاحة وترتيب المفاتيح وتفاصيل التنسيق الأخرى تشتت الانتباه عن البيانات. أما هذه الأداة فتقرأ النسختين بيانات، فلا تُحتسب إلا الاختلافات الحقيقية: إذا كان المحتوى واحدًا بمسافات أو ترتيب مختلف تخرج القوائم الثلاث فارغة. وعندما يوجد قسم في الجانبين تدخل المقارنة إليه وتشير إلى أعمق مدخل تغيّر، مثل /profile/active في المثال. وتُقارن القوائم كاملة، فإضافة editor إلى roles تعطي تغييرًا واحدًا مع القائمتين القديمة والجديدة.
متى تفيد وما الذي يجب الانتباه إليه
قبل نشر إعدادات جديدة يمكن لمراجعة أن توقف التغيير إذا كان بين المحذوفات إعداد محمي، ويمكن لفحص تلقائي أن يتأكد أن المسارات المعتمدة وحدها تغيّرت، ويمكن للتدقيق أن يحفظ الفرق المختصر بدل وثيقتين كبيرتين. انظر دائمًا إلى نوع الاختلاف لا إلى المسار وحده: فحذف قيمة وإضافة أخرى في مكان آخر لا يعني ما يعنيه تعديل قيمة موجودة. ويجب أن تكون النسختان سجلين بأسماء في المستوى الأول، لا قائمة ولا قيمة منفردة.
كيف تقرأ قائمة الاختلافات
تقسم النتيجة الفروق إلى ثلاث مجموعات: المضاف والمحذوف والمتغير. لا يظهر العنصر المضاف إلا في الكائن المحدّث، ولا يظهر المحذوف إلا في الأصلي، أما المتغير فيتضمن القيمة السابقة واللاحقة. تتحول الشرطة المائلة داخل اسم المفتاح إلى ~1 وتتحول علامة التلدة إلى ~0، وبذلك لا تختلط أسماء المفاتيح بالمستويات المتداخلة.
تسير الأداة على المفاتيح بترتيب ثابت، فتنتج إجابة مستقرة. يلخص قسم counts عدد العناصر في كل فئة والإجمالي. وإذا كانت القوائم الثلاث فارغة، فالكائنان متساويان بنيوياً حتى لو اختلفت المسافات أو طريقة ترتيب المفاتيح في النص الأصلي.
التعامل مع الكائنات المتداخلة والمصفوفات
عندما يحمل المفتاح نفسه كائناً في الجانبين، تتابع المقارنة إلى الخاصية الدقيقة المختلفة. فإذا كان التغيير الوحيد في profile.active، يكون المسار /profile/active. أما المفتاح الموجود في جانب واحد فقط فيُسجل مرة واحدة مع قيمته الكاملة، من دون إنشاء سجل لكل عنصر فرعي.
تُقارن القيم الأولية وnull مباشرة، ويُعد تغير النوع تغييراً أيضاً.
حالات الاستخدام
مراجعة إصدارات الإعداد
قارنوا الإعداد المنشور بالنسخة المرشحة وأظهروا التغييرات البنيوية من دون ضوضاء المسافات أو ترتيب المفاتيح.
حماية الإعدادات المعتمدة
افحصوا المسارات في CI وأوقفوا النشر عند إزالة خيار محمي أو تغييره.
الأسئلة الشائعة
هل يُعد اختلاف ترتيب المفاتيح تغييراً؟
لا. تقارن الأداة المفاتيح والقيم، لذلك لا ينشأ فرق من اختلاف ترتيب التسلسل وحده.
كيف تُقارن المصفوفات؟
تُقارن كقيم مرتبة كاملة، وأي تعديل أو إضافة أو حذف أو إعادة ترتيب يجعل المصفوفة متغيرة.
كيف أقرأ المسار المذكور مع كل اختلاف؟
يبدأ المسار بشرطة مائلة وينزل مستوى واحدًا مع كل شرطة: فالمسار /profile/name يشير إلى الاسم داخل profile. وتُكتب الشرطة المائلة داخل الاسم ~1 والتيلدا ~0، حتى لا يختلط اسم بمستوى.
هل يظهر التغيير داخل قسم ما بشكل منفصل؟
نعم. عندما تحتوي النسختان على القسم نفسه تدخل المقارنة إليه وتشير إلى أعمق مدخل مختلف. في المثال تغيّر active وحده داخل profile، فتذكر النتيجة /profile/active لا القسم كله.
ماذا يحدث إذا كان قسم كامل جديدًا؟
يُسجَّل مرة واحدة بكل محتواه، بدل مدخل مستقل لكل قيمة بداخله. وهكذا يُقرأ قسم الإعدادات المضاف حديثًا حدثًا واحدًا، لا قائمة طويلة من الإضافات المتفرقة.
أدوات ذات صلة
للمطوّرين — الوصول عبر API
كل ما في هذه الصفحة متاح برمجيًا. هذا القسم موجّه للفرق التقنية التي تريد ربط الأداة بأنظمتها الخاصة؛ بقية المستخدمين يمكنهم استخدام الأداة أعلاه مباشرة دون الحاجة لقراءة ما يلي.
الـEndpoint
صادِق على طلبك بترويسة Bearer، وأرسل طلب POST واحدًا لتدخل مهمتك قائمة التنفيذ فورًا؛ ثم تستلم النتيجة عبر webhook أو رابط موقّع.
استدعِ الخدمة من بيئتك
curl -X POST https://api.kit.forhosting.com/data/diff-json-objects \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}'const res = await fetch("https://api.kit.forhosting.com/data/diff-json-objects", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/data/diff-json-objects",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/data/diff-json-objects", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"before":{"name":"Ada","profile":{"active":true,"score":8},"roles":["reader"]},"after":{"name":"Ada","profile":{"active":false,"score":8,"city":"London"},"roles":["reader","editor"]}}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/data/diff-json-objects", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)مثال على الطلب
{
"before": {
"name": "Ada",
"profile": {
"active": true,
"score": 8
},
"roles": [
"reader"
]
},
"after": {
"name": "Ada",
"profile": {
"active": false,
"score": 8,
"city": "London"
},
"roles": [
"reader",
"editor"
]
}
}مثال على الاستجابة
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "data.diff_json_objects",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}الواجهة غير متزامنة: تستلم task_id فور الإرسال، ويمكنك الاستعلام عن الحالة بمعدل طلب واحد في الثانية.
الأسعار
السعر معلن كما تراه: لا tokens ولا نظام نقاط؛ وإن فشلت المهمة فلن تُحاسَب عليها.
الحدود
max_mb | 25 |
الأخطاء
| HTTP | الرمز | المعنى |
|---|---|---|
401 | unauthorized | مفتاح الوصول مفقود أو غير صالح؛ تحقق من ترويسة Bearer في طلبك. |
402 | insufficient_balance | رصيدك لا يكفي لتنفيذ هذه المهمة؛ أعد شحن الرصيد ثم أعد المحاولة. |
404 | unknown_type | نوع المهمة المطلوب غير موجود في الكتالوج — راجع الاسم المرسل في الطلب. |
429 | rate_limited | تجاوزت الحد المسموح من الطلبات؛ انتظر قليلًا ثم أعد المحاولة. |
ملاحظات تقنية
قد تجعل المقارنة النصية تحديث JSON صغيراً يبدو مزدحماً، لأن المسافات البادئة وترتيب المفاتيح والتنسيق تحجب تغييرات البيانات الفعلية. تقارن هذه الأداة القيم بعد تحليلها، وتصنف المفاتيح المضافة والمحذوفة والمتغيرة، وتتتبع الكائنات المتداخلة المشتركة، وتمنح كل نتيجة مسار JSON Pointer واضحاً.
كيفية قراءة فرق JSON بنيوي
يستخدم كل عنصر مسار JSON Pointer يبدأ بشرطة مائلة؛ فالمسار /profile/name يشير إلى name داخل profile.
التعامل مع الكائنات المتداخلة والمصفوفات
تُعامل المصفوفات كقيم JSON مرتبة وتُقارن كاملة؛ لذا فإن إضافة عنصر أو حذفه أو نقله أو تعديله تجعل خاصية المصفوفة متغيرة. تنطبق قاعدة أشد على قيمتَي الجذر فقط: يجب أن يكون before وafter كائنَي JSON غير فارغين من null.
استخدام الفرق في المراجعة والأتمتة
يمكنكم منع النشر عند حذف إعداد محمي، أو التأكد من تغير المسارات المعتمدة وحدها، أو حفظ فرق موجز لأغراض التدقيق. تعيد الأداة القيم الكاملة للمصفوفات، لتطبيق قواعد المجال عليها لاحقاً. وإذا كانت قيمة الجذر غير صالحة، فستظهر رسالة إدخال واضحة بدلاً من فرق فارغ ومضلل. ضع الكائن الأصلي في before والكائن المقترح في after. تعمل أداة المتصفح محلياً، بينما يكلف طلب API مبلغ $0.002 ويعيد البنية الحتمية نفسها. ولأن التنسيق وترتيب المفاتيح لا يولدان نتائج زائفة، تناسب الأداة ملفات الإعداد وWebhooks وأعلام الميزات والصلاحيات والاستجابات المطبّعة. عالجوا المسارات بصفتها JSON Pointer وراعوا فئة كل تغيير أيضاً.
حالات التكامل
تدقيق تطور Webhooks
سجلوا الحقول المتداخلة التي أضيفت أو حذفت أو تغيرت بين مثالين مطبّعين.
أسئلة تقنية
ما تنسيق المسار المستخدم في النتيجة؟
كل مسار هو JSON Pointer وفق نمط RFC 6901؛ تتحول الشرطة المائلة داخل المفتاح إلى ~1 والتلدة إلى ~0.
هل يمكن مقارنة مصفوفتين في المستوى الأعلى؟
لا. يجب أن يكون before وafter كائنَي JSON غير مساويين لـ null، وإلا يظهر خطأ إدخال.
ما تكلفة طلب API؟
تعمل أداة الويب محلياً مجاناً. يطبق كل طلب API السعر الأساسي المنشور وقدره $0.002.