بسیاری از خطاهای JSON از داده پیچیده یا منطق برنامه شروع نمیشوند؛ از یک کوتیشن جاافتاده، ویرگول اضافه، کلید بدون کوتیشن یا مقدار عددی نامعتبر آغاز میشوند. JSON Syntax مجموعه قوانینی است که مشخص میکند یک متن JSON از نظر ساختاری قابل Parse هست یا نه. رعایت این قواعد اولین مرحله برای انتقال داده میان API، فایل تنظیمات، پایگاه داده، مرورگر و سرویسهای مختلف است، اما بهتنهایی تضمین نمیکند که داده از نظر معنایی یا قراردادی درست باشد.
پاسخ سریع: JSON Syntax چیست؟
JSON Syntax قواعد نوشتن داده در قالب JSON است. داده باید از Object یا Array یا یک مقدار JSON معتبر تشکیل شود؛ کلیدهای Object باید داخل کوتیشن دوتایی باشند؛ Stringها با کوتیشن دوتایی نوشته شوند؛ اعضا با ویرگول جدا شوند؛ میان کلید و مقدار Colon قرار گیرد؛ و فقط انواع String، Number، Boolean، null، Object و Array استفاده شوند. JSON استاندارد Comment، کوتیشن تکی، trailing comma، undefined، NaN و Infinity را نمیپذیرد.
JSON Syntax دقیقاً چه چیزی را بررسی میکند؟
Syntax فقط شکل و ترتیب نشانهها را بررسی میکند. Parser هنگام خواندن متن، انتظار دارد آکولادها و براکتها درست بسته شوند، Stringها کامل باشند، جداکنندهها در جای مناسب قرار گیرند و مقدارها از دستور زبان JSON پیروی کنند. اگر این قواعد نقض شوند، Parse متوقف میشود و معمولاً خطایی همراه با شماره خط، ستون یا موقعیت نویسه نمایش داده میشود.
برای مثال هر دو سند زیر از نظر Syntax معتبرند:
{"age": 28}
{"age": "بیست و هشت"}
اما اگر قرارداد API انتظار Number داشته باشد، نمونه دوم از نظر معنایی یا Schema نامعتبر است. بنابراین باید میان سه سطح تفاوت قائل شد:
| سطح بررسی | پرسش اصلی | نمونه خطا |
|---|---|---|
| Syntax validity | آیا متن قابل Parse است؟ | کوتیشن بسته نشده یا ویرگول اضافه است |
| Semantic validity | آیا مقدار در دامنه مسئله معنا دارد؟ | سن منفی یا تاریخ پایان قبل از شروع |
| Schema validation | آیا نوع، فیلدها و محدودیتها مطابق قراردادند؟ | age بهجای Number بهصورت String آمده است |
ساختار پایه یک سند JSON
در کاربردهای رایج، سند JSON از یک Object یا Array در سطح ریشه تشکیل میشود. Object برای دادههای دارای نام و ویژگی مناسب است و Array برای فهرست مرتب از مقدارها استفاده میشود.
ریشه بهصورت Object
{
"id": 104,
"name": "Neda",
"active": true
}
ریشه بهصورت Array
[
{"id": 1, "name": "Ali"},
{"id": 2, "name": "Sara"}
]
در تعریف استاندارد JSON، یک مقدار مستقل مانند String، Number، Boolean یا null نیز میتواند متن JSON کامل باشد؛ با این حال برخی سامانهها، APIها یا ابزارهای قدیمی در سطح ریشه فقط Object یا Array را میپذیرند. قرارداد مقصد باید مشخص کند چه شکلی مجاز است.
قانون Object: آکولاد، کلید، Colon و Comma
Object با { شروع و با } تمام میشود. هر عضو Object یک جفت کلید و مقدار است. کلید باید String باشد، پس همیشه داخل کوتیشن دوتایی قرار میگیرد. علامت : کلید را از مقدار جدا میکند و علامت , میان اعضا قرار میگیرد.
{
"productId": 501,
"title": "Keyboard",
"available": true,
"discount": null
}
نمونههای غلط Object
{
productId: 501
}
این نمونه غلط است، چون کلید productId کوتیشن دوتایی ندارد.
{
"productId" = 501
}
این نمونه از علامت مساوی استفاده کرده است؛ JSON میان کلید و مقدار فقط Colon میپذیرد.
{
"productId": 501,
}
ویرگول پس از آخرین عضو یا trailing comma در JSON استاندارد مجاز نیست.
قانون Array: براکت و ترتیب مقدارها
Array با [ شروع و با ] تمام میشود. اعضا با ویرگول جدا میشوند و هر عضو میتواند یکی از انواع معتبر JSON باشد. ترتیب اعضا حفظ میشود.
[
"json",
2026,
true,
null,
{"level": "beginner"},
[1, 2, 3]
]
وجود نوعهای متفاوت در یک Array از نظر Syntax مجاز است، اما در طراحی API معمولاً Arrayهای همگن سادهتر، قابلپیشبینیتر و قابلاعتبارسنجیتر هستند.
ویرگول گمشده و ویرگول اضافه
["red" "green", "blue"]
میان "red" و "green" ویرگول وجود ندارد.
["red", "green", "blue",]
ویرگول آخر مجاز نیست. این الگو ممکن است در JavaScript یا قالبهای توسعهای پذیرفته شود، اما JSON معتبر نیست.
قواعد String و کوتیشن دوتایی
String در JSON باید میان کوتیشن دوتایی قرار گیرد. کوتیشن تکی، Backtick و متن بدون کوتیشن برای String مجاز نیستند.
| نمونه | وضعیت | توضیح |
|---|---|---|
"hello" | معتبر | String با کوتیشن دوتایی |
'hello' | نامعتبر | کوتیشن تکی بخشی از JSON استاندارد نیست |
`hello` | نامعتبر | Template literal مربوط به JavaScript است |
hello | نامعتبر | متن بدون کوتیشن مقدار JSON نیست |
کلیدهای Object نیز String هستند؛ بنابراین این قانون برای نام فیلدها هم برقرار است. عدد یا Boolean نمیتواند مستقیماً کلید Object باشد.
Escape در JSON String چگونه کار میکند؟
برخی نویسهها نمیتوانند بهشکل خام داخل String قرار گیرند. برای نمایش آنها باید از Backslash استفاده شود. Escape از پایان زودهنگام String یا تفسیر اشتباه نویسههای کنترلی جلوگیری میکند.
| Escape | معنا | نمونه کاربرد |
|---|---|---|
\" | کوتیشن دوتایی | نقلقول داخل متن |
\\ | Backslash | مسیر یا الگوی متنی |
\/ | Slash | اختیاری؛ Slash معمولاً بدون Escape هم مجاز است |
\b | Backspace | نویسه کنترلی |
\f | Form feed | نویسه کنترلی |
\n | خط جدید | متن چندخطی قراردادی |
\r | Carriage return | کنترل خط |
\t | Tab | فاصله Tab |
\uXXXX | کد Unicode چهاررقمی Hex | نمایش نویسه با Escape یونیکد |
{
"quote": "او گفت: \"سلام\"",
"path": "C:\\data\\file.json",
"lines": "خط اول\nخط دوم",
"tabbed": "نام\tمقدار"
}
خط جدید واقعی و خام داخل String مجاز نیست. برای متن چندخطی باید از \n استفاده کنید یا متن را در چند String/ساختار جدا مدل کنید.
Unicode و کاراکترهای فارسی
JSON برای متن Unicode طراحی شده است؛ بنابراین نویسههای فارسی میتوانند مستقیماً نوشته شوند و لازم نیست همیشه به \uXXXX تبدیل شوند.
{
"language": "فارسی",
"greeting": "سلام دنیا"
}
Escape یونیکد زمانی مفید است که سیستم تولیدکننده محدودیت نمایش داشته باشد، اما استفاده افراطی از آن خوانایی فایل را کاهش میدهد. همچنین Encoding انتقال، معمولاً UTF-8، باید در لایه فایل یا HTTP درست تنظیم شود.
قواعد Number در JSON
Number میتواند منفی، اعشاری یا دارای نمای علمی باشد، اما قواعد آن محدودتر از Literalهای عددی بعضی زبانهاست.
{
"count": 12,
"temperature": -3.5,
"ratio": 0.75,
"distance": 1.2e6
}
اعداد معتبر و نامعتبر
| مقدار | وضعیت | دلیل |
|---|---|---|
0 | معتبر | صفر مستقل مجاز است |
-12 | معتبر | علامت منفی مجاز است |
3.14 | معتبر | رقم دو طرف ممیز وجود دارد |
6.02e23 | معتبر | نمای علمی معتبر |
+12 | نامعتبر | علامت مثبت ابتدایی مجاز نیست |
01 | نامعتبر | صفر ابتدایی برای عدد صحیح مجاز نیست |
.5 | نامعتبر | قبل از ممیز باید رقم باشد |
5. | نامعتبر | بعد از ممیز باید رقم باشد |
1,000 | نامعتبر | جداکننده هزارگان بخشی از Number نیست |
NaN | نامعتبر | مقدار JSON استاندارد نیست |
Infinity | نامعتبر | مقدار JSON استاندارد نیست |
درستی Syntax عدد، حفظ دقت آن را تضمین نمیکند. Runtime مقصد ممکن است اعداد بسیار بزرگ یا Decimalهای حساس را گرد کند. برای شناسههای بزرگ، رقمهای دارای صفر ابتدایی یا Decimal دقیق باید قرارداد مناسبی مانند String یا واحد صحیح کوچک تعریف شود.
Boolean و null چگونه نوشته میشوند؟
سه Literal ویژه JSON عبارتاند از true، false و null. آنها باید دقیقاً با حروف کوچک و بدون کوتیشن نوشته شوند.
{
"active": true,
"archived": false,
"deletedAt": null
}
| نمونه | نوع واقعی یا وضعیت |
|---|---|
true | Boolean معتبر |
"true" | String معتبر، نه Boolean |
True | JSON نامعتبر |
NULL | JSON نامعتبر |
undefined | JSON نامعتبر |
Whitespace در JSON
فاصله، Tab، خط جدید و Carriage return میان Tokenها معمولاً نادیده گرفته میشوند. به همین دلیل نسخه فشرده و نسخه خوانا از نظر داده یکساناند.
{"id":1,"name":"Ali","active":true}
{
"id": 1,
"name": "Ali",
"active": true
}
Whitespace داخل String بخشی از مقدار است و حذف آن میتواند معنا را تغییر دهد. Formatter فقط فاصلههای ساختاری را تنظیم میکند و نباید محتوای String را تغییر دهد.
آیا JSON از Comment پشتیبانی میکند؟
JSON استاندارد Comment ندارد. نه Comment تکخطی با // و نه Comment بلوکی با /* ... */ معتبر است.
{
// شناسه کاربر
"id": 42
}
این نمونه JSON معتبر نیست. برای توضیحات میتوان فیلد مستندشدهای مانند "description" تعریف کرد، مستندات را جدا نگه داشت یا از قالب دیگری استفاده کرد که Comment را رسماً پشتیبانی میکند. حذف Comment با Regex نیز خطرناک است، چون توالیهای مشابه ممکن است داخل String باشند.
کلیدهای تکراری: چرا حتی با Parse موفق خطرناکاند؟
Object زیر دو کلید یکسان دارد:
{
"role": "user",
"role": "admin"
}
برخی Parserها آخرین مقدار را نگه میدارند، برخی ممکن است اولین مقدار را انتخاب کنند و برخی امکان گزارش خطا دارند. این اختلاف رفتار میتواند باعث ناسازگاری و حتی مشکل امنیتی شود؛ برای مثال یک لایه امنیتی مقدار اول را بخواند و لایه کسبوکار مقدار دوم را. بهترین روش این است که کلیدها در هر Object یکتا باشند و Validator یا Parser سختگیر آن را کنترل کند.
ساختارهای تودرتو و بستن درست نشانهها
JSON میتواند Object و Array را در چند سطح ترکیب کند. در چنین ساختاری هر { باید با } و هر [ باید با ] متناظر بسته شود.
{
"orderId": "A-1007",
"customer": {
"name": "Leila",
"addresses": [
{
"type": "shipping",
"city": "Shiraz"
}
]
},
"items": [
{"sku": "K10", "quantity": 2},
{"sku": "M20", "quantity": 1}
]
}
Indentation بخشی از Syntax نیست، اما در پیدا کردن براکت یا آکولاد گمشده بسیار مؤثر است. استفاده از Formatter روی JSON قابل Parse، ساختار تودرتو را آشکارتر میکند؛ اگر Parse شکست خورده باشد، ابتدا باید خطای Syntax رفع شود.
نمونه کامل JSON صحیح و نسخههای خراب آن
نسخه صحیح
{
"user": {
"id": 27,
"name": "Mina",
"roles": ["editor", "reviewer"],
"profile": {
"bio": "نویسنده و ویراستار",
"website": null
},
"verified": true
}
}
نسخه خراب: کوتیشن تکی و کلید بدون کوتیشن
{
user: {
'id': 27
}
}
نسخه خراب: ویرگول گمشده
{
"id": 27
"name": "Mina"
}
نسخه خراب: براکت ناسازگار
{
"roles": ["editor", "reviewer"}
]
نسخه خراب: String بستهنشده
{
"name": "Mina
}
پیام خطای Parser را چگونه بخوانیم؟
پیام خطا در زبانها و کتابخانهها متفاوت است، اما معمولاً یکی از این اطلاعات را میدهد: Token غیرمنتظره، پایان غیرمنتظره فایل، شماره خط و ستون، یا موقعیت نویسه. محل گزارششده همیشه دقیقاً محل اشتباه اصلی نیست؛ Parser ممکن است چند نویسه بعد تازه متوجه ناسازگاری شود.
- ابتدا خط و ستون گزارششده را پیدا کنید.
- چند خط قبل را نیز بررسی کنید؛ ویرگول یا کوتیشن گمشده ممکن است آنجا باشد.
- جفت آکولادها و براکتها را کنترل کنید.
- اطمینان حاصل کنید کلیدها و Stringها کوتیشن دوتایی دارند.
- trailing comma، Comment و Literalهای غیرمجاز را حذف کنید.
- پس از اصلاح، دوباره Parse و سپس Schema validation را اجرا کنید.
Parse کردن JSON در زبانهای مختلف
بهتر است JSON را با Parser استاندارد زبان بخوانید، نه با Split، Regex یا جایگزینی دستی. Parser علاوه بر ساختار، Escape و Unicode را نیز درست مدیریت میکند.
JavaScript
const text = '{"name":"Sara","active":true}';
try {
const data = JSON.parse(text);
console.log(data.name);
} catch (error) {
console.error("Invalid JSON:", error.message);
}
Python
import json
text = '{"name":"Sara","active":true}'
try:
data = json.loads(text)
print(data["name"])
except json.JSONDecodeError as error:
print(f"Invalid JSON at line {error.lineno}, column {error.colno}")
C# با System.Text.Json
using System.Text.Json;
var text = "{\"name\":\"Sara\",\"active\":true}";
try
{
using var document = JsonDocument.Parse(text);
Console.WriteLine(document.RootElement.GetProperty("name").GetString());
}
catch (JsonException ex)
{
Console.WriteLine($"Invalid JSON: {ex.Message}");
}
گزینههای Parser ممکن است رفتار را تغییر دهند؛ برای مثال بعضی کتابخانهها امکان پذیرش Comment یا trailing comma را بهصورت غیراستاندارد فراهم میکنند. اگر داده میان چند سامانه ردوبدل میشود، خروجی را بر اساس JSON استاندارد تولید کنید، نه قابلیتهای تساهلآمیز یک Parser خاص.
تولید JSON: از الحاق رشتهها پرهیز کنید
ساخت JSON با چسباندن رشتهها مستعد خطای Escape، کوتیشن و Injection است.
const name = 'Sara "Admin"';
const unsafe = '{"name":"' + name + '"}';
روش بهتر این است که ابتدا ساختار داده بومی زبان ساخته شود و سپس Serializer استاندارد خروجی JSON تولید کند.
const payload = {
name: 'Sara "Admin"',
active: true
};
const safeJson = JSON.stringify(payload);
Serializer کوتیشنها، Backslash و نویسههای کنترلی را درست Escape میکند. با این حال هنوز باید بررسی شود که داده از نظر Schema، مجوزها و منطق کسبوکار معتبر است.
خطاهای رایج JSON Syntax و روش رفع آنها
| خطا | نمونه علت | راهحل |
|---|---|---|
| Unexpected token | کوتیشن تکی، Comment یا کاراکتر اضافی | Token گزارششده و چند نویسه قبل را بررسی کنید |
| Unexpected end | String، Object یا Array بسته نشده | کوتیشن و جفت نشانههای باز/بسته را کنترل کنید |
| Expected comma | میان دو عضو ویرگول نیست | بعد از عضو قبلی Comma اضافه کنید |
| Trailing comma | پس از آخرین عضو ویرگول آمده | آخرین Comma را حذف کنید |
| Invalid escape | Backslash با توالی نامعتبر | Backslash را Escape یا توالی معتبر استفاده کنید |
| Invalid number | صفر ابتدایی، ممیز ناقص یا NaN | عدد را مطابق دستور زبان JSON بازنویسی کنید |
| Duplicate key | یک نام فیلد دوبار آمده | کلیدها را یکتا کنید و منشأ Merge را اصلاح کنید |
JSON، JavaScript Object و JSON5 یکسان نیستند
JSON از Syntax شیء JavaScript الهام گرفته، اما زیرمجموعهای محدود و مستقل برای تبادل داده است. در JavaScript ممکن است کلید بدون کوتیشن، کوتیشن تکی، trailing comma، مقدار undefined یا Expression وجود داشته باشد؛ این موارد لزوماً JSON نیستند. JSON5 نیز قالب جداگانهای است که برخی محدودیتها را کاهش میدهد، اما Parser معمولی JSON آن را نمیپذیرد.
| ویژگی | JSON | JavaScript Object Literal |
|---|---|---|
| کلید بدون کوتیشن | مجاز نیست | در بسیاری موارد مجاز است |
| کوتیشن تکی | مجاز نیست | مجاز است |
| Comment | مجاز نیست | مجاز است |
| trailing comma | مجاز نیست | در Syntax مدرن مجاز است |
| Function یا Expression | مجاز نیست | میتواند وجود داشته باشد |
| undefined و NaN | مجاز نیست | مقدارهای JavaScript هستند |
نکات امنیتی هنگام دریافت JSON
معتبر بودن Syntax به معنی امن بودن داده نیست. ورودی JSON همچنان داده غیرقابل اعتماد است و باید محدود، اعتبارسنجی و پاکسازی منطقی شود.
- محدودیت اندازه: قبل از Parse، سقف منطقی برای Body یا فایل تعیین کنید.
- عمق تودرتویی: Objectها و Arrayهای بسیار عمیق میتوانند منابع Parser را مصرف کنند.
- تعداد اعضا: Array یا Object بسیار بزرگ ممکن است حافظه و CPU زیادی مصرف کند.
- کلید تکراری: از Parser یا Validationای استفاده کنید که رفتار روشن و ترجیحاً خطا داشته باشد.
- Mass assignment: همه فیلدهای ورودی را مستقیماً روی مدل حساس نگاشت نکنید.
- خروجی HTML یا SQL: Parse موفق JSON نیاز به Escape زمینهای و Query پارامتری را حذف نمیکند.
- Polymorphic deserialization: فعالکردن نوعدهی پویا برای ورودی غیرقابل اعتماد میتواند خطرناک باشد.
نکات عملکرد برای JSONهای بزرگ
برای فایلهای کوچک، Parse کامل معمولاً سادهترین روش است. در دادههای بزرگ باید مصرف حافظه و زمان پردازش سنجیده شود.
- در صورت امکان از Streaming parser استفاده کنید تا کل سند همزمان در حافظه قرار نگیرد.
- محدودیت حجم و عمق را قبل یا هنگام Parse اعمال کنید.
- برای جریان رکوردهای مستقل، قالبهای خطمحور مانند NDJSON میتوانند مناسبتر باشند.
- Pretty-print برای توسعه مفید است، اما در انتقال پرتعداد حجم بیشتری ایجاد میکند.
- Minify فقط Whitespace ساختاری را حذف میکند و داده را فشردهسازی واقعی نمیکند؛ فشردهسازی انتقال وظیفه لایههایی مانند HTTP compression است.
بهترین روشهای نوشتن JSON معتبر
- JSON را با Serializer استاندارد تولید کنید، نه الحاق رشتهها.
- همه کلیدها و Stringها را با کوتیشن دوتایی بنویسید.
- پس از آخرین عضو Object یا Array ویرگول قرار ندهید.
- از Comment و Literalهای مخصوص زبان برنامهنویسی استفاده نکنید.
- کلیدهای هر Object را یکتا نگه دارید.
- برای تاریخ، Decimal، شناسه بزرگ و Binary قرارداد صریح تعریف کنید.
- Syntax validation را از Schema validation جدا در نظر بگیرید.
- ورودی را از نظر اندازه، عمق و تعداد اعضا محدود کنید.
- Encoding را بهطور ثابت، ترجیحاً UTF-8، مدیریت کنید.
- در Pipeline و تستها نمونههای نامعتبر را نیز آزمایش کنید.
چکلیست سریع JSON Syntax
- آیا ریشه یک مقدار JSON معتبر، معمولاً Object یا Array، است؟
- آیا همه کلیدهای Object داخل کوتیشن دوتایی هستند؟
- آیا میان کلید و مقدار Colon قرار دارد؟
- آیا اعضا با Comma جدا شدهاند؟
- آیا پس از آخرین عضو trailing comma وجود ندارد؟
- آیا تمام Stringها بسته و نویسههای لازم Escape شدهاند؟
- آیا آکولادها و براکتها درست جفت شدهاند؟
- آیا فقط
true،falseوnullبا حروف کوچک استفاده شدهاند؟ - آیا Numberها صفر ابتدایی، ممیز ناقص، NaN یا Infinity ندارند؟
- آیا Comment یا Syntax مخصوص JavaScript وارد فایل نشده است؟
- آیا کلید تکراری وجود ندارد؟
- آیا پس از Parse، Schema و قواعد کسبوکار نیز بررسی میشوند؟
جمعبندی
JSON Syntax زبان مشترک و سختگیرانهای برای نوشتن داده قابل Parse فراهم میکند: Object با آکولاد، Array با براکت، کلید و String با کوتیشن دوتایی، Colon میان کلید و مقدار، Comma میان اعضا و فقط شش نوع مقدار معتبر. کوتیشن تکی، Comment، trailing comma، undefined، NaN و Infinity بخشی از JSON استاندارد نیستند. پس از رفع خطاهای Syntax، مرحله کار تمام نمیشود؛ نوعها، فیلدهای اجباری، محدودیتها، امنیت و معنای داده باید با Schema و منطق برنامه بررسی شوند.