در بسیاری از برنامهها داده بهصورت متن JSON وارد میشود: پاسخ یک API، محتوای فایل تنظیمات، مقدار ذخیرهشده در پایگاه داده یا پیامی که از صف دریافت شده است. تا وقتی این متن Parse نشود، برنامه معمولاً نمیتواند مانند یک Object یا Array واقعی به فیلدها و اعضای آن دسترسی داشته باشد. JSON Parse فرایند خواندن متن JSON، بررسی Syntax و تبدیل آن به ساختار داده بومی زبان برنامهنویسی است.
پاسخ سریع: JSON Parse چیست؟
JSON Parse یعنی تبدیل یک String حاوی JSON معتبر به داده قابل استفاده در برنامه؛ برای مثال Object، Array، Dictionary، List یا مدل تایپشده. Parser ابتدا Syntax را بررسی میکند و در صورت معتبر بودن، Stringها، Numberها، Booleanها، null، Objectها و Arrayها را به نوعهای متناظر زبان مقصد تبدیل میکند. Parse موفق فقط معتبر بودن Syntax را نشان میدهد و جای Schema validation، بررسی مجوز، محدودیت حجم یا قواعد کسبوکار را نمیگیرد.
چرا JSON Parse ضروری است؟
متن زیر برای انسان شبیه یک Object است، اما برای Runtime فقط یک رشته از نویسههاست:
{"id": 42, "name": "Sara", "active": true}
تا قبل از Parse، دسترسی مستقیم به name یا بررسی مقدار active ممکن نیست. بعد از Parse، داده به ساختاری تبدیل میشود که زبان مقصد آن را میشناسد. نتیجه در JavaScript معمولاً Object است، در Python میتواند dict باشد، در C# میتواند JsonDocument، Dictionary یا یک کلاس مشخص باشد و در Java اغلب به Tree Model یا POJO تبدیل میشود.
| مرحله | ورودی یا خروجی | هدف |
|---|---|---|
| دریافت | متن، Stream یا Byte | گرفتن داده از فایل، HTTP، صف یا دیتابیس |
| Decode متن | Byte به String، معمولاً UTF-8 | تفسیر درست نویسهها |
| Parse | JSON text به ساختار داده | تشخیص Tokenها و ساخت Object/Array |
| Validation | داده Parseشده | بررسی نوعها، فیلدهای اجباری و محدودیتها |
| استفاده | مدل معتبر | اجرای منطق برنامه |
JSON Parser چگونه کار میکند؟
Parser متن را به Tokenهایی مانند آکولاد، براکت، String، Number، Colon، Comma و Literalهای true، false و null تقسیم میکند. سپس بر اساس دستور زبان JSON، رابطه میان Tokenها را میسنجد و یک ساختار درختی میسازد. Objectها شامل جفت کلید و مقدار هستند و Arrayها ترتیب اعضا را حفظ میکنند.
- ورودی و Encoding خوانده میشود.
- Whitespace ساختاری نادیده گرفته میشود.
- Stringها و Escapeها تفسیر میشوند.
- عددها و Literalها تشخیص داده میشوند.
- ساختار تودرتو با Stack یا الگوریتم مشابه دنبال میشود.
- در صورت خطا، Parse متوقف و موقعیت تقریبی گزارش میشود.
- در صورت موفقیت، ساختار داده یا مدل نهایی برگردانده میشود.
پیادهسازی دقیق کتابخانهها متفاوت است. بعضی Parserها کل سند را در حافظه میسازند، بعضی بهصورت Streaming Tokenها را میخوانند و بعضی مستقیماً داده را به مدل تایپشده تبدیل میکنند.
تفاوت Parse، Validate و Deserialize
این سه اصطلاح نزدیکاند، اما یکسان نیستند. استفاده دقیق از آنها از خطاهای طراحی جلوگیری میکند.
| عملیات | پرسش اصلی | خروجی معمول |
|---|---|---|
| Parse | آیا متن از نظر Syntax قابل خواندن است؟ | درخت عمومی، Object یا Array |
| Deserialize | آیا داده به نوع یا کلاس مقصد تبدیل میشود؟ | نمونه کلاس، Record یا مدل دامنه |
| Schema validation | آیا ساختار و مقدارها مطابق قراردادند؟ | نتیجه معتبر/نامعتبر و خطاها |
| Business validation | آیا داده برای این عملیات منطقی و مجاز است؟ | پذیرش یا رد در سطح برنامه |
برای مثال {"age":"20"} از نظر Syntax معتبر و قابل Parse است. اگر مدل انتظار عدد داشته باشد، Deserialize ممکن است شکست بخورد یا با تبدیل ضمنی انجام شود. حتی اگر به عدد ۲۰ تبدیل شود، هنوز باید قواعدی مانند بازه مجاز سن بررسی شوند.
JSON Parse در JavaScript
در JavaScript متد استاندارد JSON.parse() یک String JSON را به مقدار JavaScript تبدیل میکند.
const text = '{"id":42,"name":"Sara","roles":["editor","author"]}';
const user = JSON.parse(text);
console.log(user.name); // Sara
console.log(user.roles[0]); // editor
اگر Syntax خراب باشد، SyntaxError رخ میدهد. ورودی خارجی باید داخل try...catch پردازش شود:
function safeParseJson(text) {
try {
return { ok: true, value: JSON.parse(text), error: null };
} catch (error) {
return { ok: false, value: null, error: error.message };
}
}
const result = safeParseJson('{"active": true,}');
if (!result.ok) {
console.error('Invalid JSON:', result.error);
}
استفاده از reviver
پارامتر دوم JSON.parse() تابع reviver است و اجازه میدهد مقدارها هنگام بازسازی تغییر کنند. تاریخ JSON نوع مستقل ندارد و معمولاً String است؛ بنابراین میتوان رشتههای قراردادی تاریخ را تبدیل کرد:
const order = JSON.parse(
'{"createdAt":"2026-08-06T10:30:00Z","total":120}',
(key, value) => key === 'createdAt' ? new Date(value) : value
);
console.log(order.createdAt instanceof Date); // true
تبدیل خودکار هر String شبیه تاریخ ممکن است داده را ناخواسته تغییر دهد. reviver باید فقط برای فیلدها و قراردادهای مشخص استفاده شود.
JSON Parse در Python
ماژول استاندارد json برای متن از json.loads() و برای فایل از json.load() استفاده میکند.
import json
text = '{"id": 42, "name": "Sara", "active": true}'
data = json.loads(text)
print(data["name"])
print(type(data)) # dict
برای مدیریت خطا از JSONDecodeError استفاده کنید:
import json
try:
data = json.loads('{"items": [1, 2,]}')
except json.JSONDecodeError as error:
print(f"line={error.lineno}, column={error.colno}")
print(error.msg)
خواندن مستقیم فایل
import json
with open("config.json", "r", encoding="utf-8") as file:
config = json.load(file)
print(config.get("environment"))
تعیین صریح UTF-8 از وابستگی به Encoding پیشفرض سیستم جلوگیری میکند. برای دادههای مالی نیز میتوان با گزینههایی مانند parse_float عدد اعشاری را به Decimal تبدیل کرد تا خطای ممیز شناور کاهش یابد.
JSON Parse و Deserialize در C#
در .NET، فضای نام System.Text.Json چند روش ارائه میدهد. وقتی مدل مشخص دارید، Deserialize مستقیم به کلاس معمولاً خواناتر و امنتر است.
using System.Text.Json;
public sealed record User(int Id, string Name, bool Active);
string json = """{"Id":42,"Name":"Sara","Active":true}""";
User? user = JsonSerializer.Deserialize<User>(json);
Console.WriteLine(user?.Name);
برای داده پویا یا بررسی انتخابی فیلدها میتوان از JsonDocument استفاده کرد:
using System.Text.Json;
using JsonDocument document = JsonDocument.Parse(
"""{"meta":{"count":2},"items":["A","B"]}"""
);
JsonElement root = document.RootElement;
int count = root.GetProperty("meta").GetProperty("count").GetInt32();
string first = root.GetProperty("items")[0].GetString()!;
مدیریت JsonException
try
{
var value = JsonSerializer.Deserialize<User>(input);
}
catch (JsonException ex)
{
Console.WriteLine($"Path: {ex.Path}");
Console.WriteLine($"Line: {ex.LineNumber}, Byte: {ex.BytePositionInLine}");
}
نام فیلدها، حساسیت به حروف، Number handling و رفتار فیلدهای ناشناخته به گزینههای Serializer و نسخه Runtime وابسته است. قرارداد API و تنظیمات برنامه باید صریح باشند.
JSON Parse در Java
Java در کتابخانه پایه یک API واحد و عمومی برای JSON ندارد و معمولاً از کتابخانههایی مانند Jackson استفاده میشود. نمونه زیر متن را به Tree Model تبدیل میکند:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
String json = "{\"id\":42,\"name\":\"Sara\"}";
JsonNode root = mapper.readTree(json);
System.out.println(root.get("name").asText());
برای مدل تایپشده:
public record User(int id, String name, boolean active) {}
User user = mapper.readValue(
"{\"id\":42,\"name\":\"Sara\",\"active\":true}",
User.class
);
رفتار فیلد ناشناخته، تاریخ، Enum و تبدیل نوعها به تنظیمات ObjectMapper وابسته است. تنظیمات تساهلآمیز ممکن است سازگاری را بالا ببرد، اما خطای داده را پنهان کند.
مثال واقعی: Parse پاسخ API
فرض کنید API سفارشها این پاسخ را برمیگرداند:
{
"requestId": "req-91",
"items": [
{"id": 1001, "title": "Keyboard", "price": 89.5},
{"id": 1002, "title": "Mouse", "price": 39.0}
],
"nextCursor": null
}
یک مسیر امن پردازش فقط به JSON.parse ختم نمیشود:
- وضعیت HTTP و نوع محتوا بررسی شود.
- محدودیت اندازه پاسخ اعمال شود.
- متن با Encoding درست Decode شود.
- JSON Parse و خطای Syntax مدیریت شود.
- وجود
itemsو Array بودن آن بررسی شود. - نوع و محدوده
idوpriceاعتبارسنجی شود. - مقدارهای غیرمنتظره پیش از ورود به منطق مالی رد شوند.
در غیر این صورت، سندی مانند {"items":"not-an-array"} با موفقیت Parse میشود، ولی در ادامه برنامه را دچار خطا میکند.
خطاهای رایج هنگام JSON Parse
۱. ارسال Object بهجای String
در JavaScript، JSON.parse() برای متن JSON است. اگر داده از قبل Object باشد، Parse دوباره لازم نیست.
const data = { id: 1 };
// اشتباه: JSON.parse(data)
console.log(data.id);
۲. Parse دوباره یا Double Parsing
گاهی کتابخانه HTTP پاسخ را خودکار Parse کرده است. Parse دوباره باعث خطا یا پیچیدگی غیرضروری میشود. نوع واقعی مقدار را در مرز ورودی مشخص کنید.
۳. اشتباه گرفتن JavaScript Object Literal با JSON
// JavaScript معتبر، اما JSON نامعتبر
const text = "{name: 'Sara', active: true}";
کلید بدون کوتیشن و String با کوتیشن تکی در JSON استاندارد پذیرفته نمیشود.
۴. وجود BOM یا نویسه نامرئی
برخی فایلها با Byte Order Mark یا نویسههای کنترلی ناخواسته شروع میشوند. کتابخانهها رفتار یکسانی ندارند. Encoding و منبع تولید فایل را بررسی کنید و حذف نویسه را فقط با شناخت دقیق انجام دهید.
۵. فرض نوع نادرست پس از Parse
Parser ممکن است ریشه را String، Number، Boolean، null، Object یا Array برگرداند. قبل از دسترسی به اعضا، نوع ریشه را بررسی کنید.
۶. از دست رفتن دقت Number
شناسه بسیار بزرگ ممکن است در Runtimeهای مبتنی بر IEEE 754 دقیق باقی نماند. شناسههای طولانی و Decimal مالی باید با قرارداد مناسب، مثلاً String یا نوع Decimal، منتقل شوند.
۷. تاریخ بهعنوان String باقی میماند
Parse عمومی نمیداند کدام String تاریخ است. تبدیل تاریخ باید بر اساس فرمت و Time Zone قراردادی انجام شود.
چگونه خطای Parse را عیبیابی کنیم؟
- متن خام واقعی را ثبت کنید، اما داده حساس را حذف یا ماسک کنید.
- خط، ستون یا Byte position گزارششده را پیدا کنید.
- چند Token قبل از محل خطا را هم بررسی کنید؛ علت ممکن است کوتیشن یا Comma قبلی باشد.
- مطمئن شوید ورودی HTML، صفحه خطای Proxy یا متن ساده نیست.
- Content-Type و Encoding را بررسی کنید.
- JSON را با ابزار اعتبارسنجی JSON بررسی کنید.
- پس از رفع Syntax، Schema و نوع فیلدها را جداگانه کنترل کنید.
| پیام یا نشانه | علت محتمل | اقدام |
|---|---|---|
| Unexpected token در ابتدای ورودی | پاسخ HTML، متن خطا یا حرف اضافی | متن خام و Content-Type را ببینید |
| Unexpected end of input | JSON ناقص یا Stream قطعشده | طول پاسخ و بستهشدن براکتها را بررسی کنید |
| Expected comma or delimiter | Comma یا Colon گمشده | عضو قبلی Object/Array را بررسی کنید |
| Invalid escape | Backslash اشتباه داخل String | Escapeهای مجاز JSON را استفاده کنید |
| Type conversion failed | Syntax درست ولی مدل ناسازگار | نوع DTO و قرارداد API را مقایسه کنید |
امنیت JSON Parse
Parse کردن JSON اجرای کد نیست، اما ورودی غیرقابل اعتماد همچنان میتواند خطر ایجاد کند. سند بسیار بزرگ یا با عمق زیاد حافظه و CPU را مصرف میکند. کلیدهای تکراری میتوانند میان Parserها رفتار متفاوت ایجاد کنند. داده Parseشده نیز ممکن است در SQL، HTML، Shell یا مسیر فایل استفاده شود و در آن لایه نیازمند کنترل جداگانه باشد.
- برای اندازه Body، تعداد اعضا، طول String و عمق Nesting محدودیت بگذارید.
- Timeout و Cancellation را در پردازش Streamهای بزرگ در نظر بگیرید.
- کلیدهای تکراری را رد کنید یا سیاست یکنواخت داشته باشید.
- پس از Parse از allowlist فیلدها و Schema استفاده کنید.
- هرگز داده را بهدلیل Parse موفق، قابل اعتماد فرض نکنید.
- برای خروجی HTML، SQL و Command از Encoding یا API پارامتری همان Context استفاده کنید.
- پیام خطای داخلی و Stack trace را مستقیماً به کاربر نهایی نمایش ندهید.
استفاده از eval برای تبدیل JSON اشتباه و ناامن است. JSON باید با Parser اختصاصی خوانده شود، نه موتور اجرای JavaScript یا زبان دیگر.
عملکرد: DOM Parsing یا Streaming؟
در DOM یا Tree Parsing کل سند در حافظه به یک درخت تبدیل میشود. این روش برای فایلهای کوچک و متوسط ساده است، اما برای داده بسیار بزرگ حافظه زیادی مصرف میکند. Streaming Parser توکنها را بهترتیب میخواند و لازم نیست همه سند همزمان در حافظه باشد.
| روش | مزیت | محدودیت | مناسب برای |
|---|---|---|---|
| Tree/DOM | دسترسی آزاد و کدنویسی ساده | مصرف حافظه متناسب با کل سند | تنظیمات و پاسخهای معمول API |
| Typed deserialization | مدل روشن و کنترل نوع بهتر | وابستگی به قرارداد DTO | APIهای پایدار و منطق دامنه |
| Streaming | حافظه کمتر و شروع پردازش زودتر | کدنویسی پیچیدهتر و دسترسی ترتیبی | فایل بزرگ و جریان داده |
| NDJSON line-by-line | پردازش مستقل هر رکورد | ساختار با JSON معمولی متفاوت است | Log و Pipeline داده |
برای بهبود عملکرد، فقط فیلدهای لازم را بخوانید، از Parse و Serialize تکراری جلوگیری کنید، پاسخهای غیرضروری را نگه ندارید و پیش از تخصیص حافظه اندازه ورودی را محدود کنید. Benchmark باید با داده واقعی و کتابخانه مورد استفاده انجام شود.
بهترین روشهای JSON Parse
- مرزهای سیستم را مشخص کنید: کجا Byte به متن و کجا متن به مدل تبدیل میشود.
- خطای Syntax را از خطای Schema و خطای کسبوکار جدا گزارش کنید.
- برای قراردادهای پایدار از مدل تایپشده استفاده کنید.
- برای داده پویا فقط فیلدهای لازم را با بررسی نوع بخوانید.
- Encoding را صریحاً UTF-8 تنظیم کنید، مگر قرارداد دیگری دارید.
- Decimal مالی، شناسه بزرگ، تاریخ و Time Zone را صریح مدل کنید.
- Parser تساهلآمیز را بدون دلیل فعال نکنید؛ Comment و trailing comma قابلیت حمل را کاهش میدهند.
- برای خطاهای ورودی Log قابل پیگیری بسازید، اما Token، رمز و داده شخصی را ماسک کنید.
- قبل از Parse محدودیت اندازه و بعد از Parse محدودیت ساختار اعمال کنید.
- نمونههای معتبر، نامعتبر، ناقص و مرزی را در تستها پوشش دهید.
چکلیست Parse امن و قابل اعتماد
- آیا ورودی واقعاً JSON text است و قبلاً Parse نشده؟
- آیا Content-Type و UTF-8 درستاند؟
- آیا اندازه و عمق ورودی محدود شده است؟
- آیا خطای Parser مدیریت میشود؟
- آیا نوع ریشه Object یا Array مطابق انتظار است؟
- آیا فیلدهای اجباری و نوع آنها اعتبارسنجی میشوند؟
- آیا عدد بزرگ، Decimal و تاریخ قرارداد روشنی دارند؟
- آیا کلیدهای ناشناخته و تکراری سیاست مشخصی دارند؟
- آیا داده حساس در Log حذف میشود؟
- آیا داده پیش از استفاده در SQL، HTML یا Shell کنترل Context-specific میشود؟
جمعبندی
JSON Parse پلی میان متن JSON و داده قابل استفاده در برنامه است. Parser Syntax را میخواند، Escapeها و نوعهای پایه را تفسیر میکند و Object یا Array یا مدل مقصد را میسازد. بااینحال Parse موفق به معنی معتبر بودن قرارداد، امن بودن داده یا درست بودن منطق نیست. یک پیادهسازی قابل اعتماد باید خطاها را مدیریت کند، Encoding و محدودیت منابع را در نظر بگیرد، نوعها و Schema را بررسی کند و برای دادههای بزرگ روش Streaming را ارزیابی کند. پیش از استفاده از ورودی واقعی، متن را با ابزار JSON Parse یا Validator بررسی کنید و تفاوت میان Parse، Deserialize و Validation را در طراحی حفظ کنید.