مقایسه کتابخانههای تجزیه و پردازش JSON
جمعبندی: APIهای بومی سریعتریناند، تجزیهکنندههای خطاپذیر offset میدهند. بر اساس سه چیز انتخاب کنید: مکان خطا، حفظ متن اصلی و صریح بودن مرزها.

جمعبندی: نخست نیاز را دستهبندی کنید، سپس پیادهسازیها را مقایسه کنید — برای مقدارهای فقطخواندنی از JSON.parse بومی، وقتی به offset نیاز دارید یا باید قالب اصلی را حفظ کنید از jsonc-parser و کتابخانههای پرسوجو یا patch را فقط در جای لازم بیفزایید؛ کتابخانههای بزرگ را بهصورت صفحهبهصفحه بارگذاری تنبل کنید و کتابخانههای بدون نگهداری را کنار بگذارید.
هر کتابخانهای ادعا میکند «سریع، کوچک و کامل» است. آنچه واقعاً از هم جدا میکند این است که وقتی مشکلی پیش میآید چقدر اطلاعات میدهد.
۱. چهار دسته بر اساس هدف
| دسته | کتابخانههای نماینده | چه چیزی را حل میکند |
|---|---|---|
| تجزیه استاندارد | JSON.parse / JSON.stringify |
نحو ↔ object، سرعت در اولویت |
| تجزیه خطاپذیر + ویرایش | jsonc-parser، json5 |
ورودی دارای کامنت، خطای دقیق تا offset، تغییر با حفظ قالببندی |
| پرسوجو | jsonpath-plus، jsonpath |
انتخاب گره با عبارت |
| تغییر | fast-json-patch، immer |
تولید/اعمال patch، بهروزرسانی تغییرناپذیر |
نخست تشخیص دهید در کدام دسته هستید، سپس پیادهسازیهای مشخص را مقایسه کنید — وگرنه بهآسانی از کتابخانه پرسوجو برای کار تجزیهکننده استفاده میکنید.
۲. مقایسه کناربهکنار
| کتابخانه | مکان خطا | تحمل (کامنت/ویرگول انتهایی) | حفظ قالب اصلی | سناریوهای مناسب |
|---|---|---|---|---|
JSON.parse |
فقط پیام و موقعیت (وابسته به موتور) | ✗ | ✗ | تجزیه پیشفرض، داده API |
jsonc-parser |
offset دقیق + کد خطا |
✓ | ✓ (modify + applyEdits) |
ویرایشگرها، فایلهای پیکربندی |
json5 |
اطلاعات خط و ستون | ✓ (سختگیرتر) | ✗ | خواندن پیکربندی JSON5 |
jsonlint |
اطلاعات خط و ستون | ✗ | ✗ | فقط مرجع، فعالانه نگهداری نمیشود |
jsonpath-plus |
خطای نحو عبارت | — | — | پرسوجو با عبارت |
fast-json-patch |
خطا در سطح عملیات | — | — | تولید و اعمال patch |
lz-string |
— | — | — | فشرده کردن JSON به URL |
پیامهای خطای JSON.parse میان موتورها بسیار متفاوتاند. V8 چیزی مانند
Unexpected token } in JSON at position 42 تولید میکند، اما دقیق بودن position به نسخه موتور بستگی دارد؛
در مقابل jsonc-parser یک { error, offset, length } ساختاریافته پایدار برمیگرداند که برای نشانگرهای ویرایشگر مناسب است.
۳. چهار نقطه تصمیم کلیدی
۳.۱ آیا به offset نیاز دارید
اگر ویرایشگر میسازید و میخواهید «کلیک روی خطا به خط متناظر بپرد»، offset ضروری است. آزمون ساده است: اگر پیام خطای شما فقط میتواند «invalid JSON» چاپ کند، کاربران باید خودشان دنبالش بگردند.
import { parse, printParseErrorCode } from 'jsonc-parser';
const errors: Array<{ error: number; offset: number; length: number }> = [];
parse(text, errors, { allowTrailingComma: true, disallowComments: false });
if (errors.length > 0) {
const firstError = errors[0];
console.error(`${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`);
}
۳.۲ آیا باید متن اصلی را حفظ کنید
فقط خواندن مقدارها → هر تجزیهکنندهای کافی است. «یک فیلد را تغییر بده و بقیه را دقیقاً همانطور که بود نگه دار» → باید از API ویرایشی استفاده کنید، نه «تجزیه → تغییر object → سریالسازی».
روش دوم از دست میدهد: کامنتها، ترتیب کلیدها (در برخی پیادهسازیها)، سبک تورفتگی، نگارش لیترال عددی (1e3 به 1000 تبدیل میشود) و شکلهای escape (\u4e2d به کاراکتر واقعی تبدیل میشود).
۳.۳ آیا رفتارهای مرزی صریحاند
پیش از انتخاب کتابخانه، مستندات را برای سه چیز بررسی کنید:
۱. کلید تکراری چگونه مدیریت میشود (نگه داشتن آخرین / خطا)؛
۲. آیا عددهای صحیح بزرگ دقت را از دست میدهند (بیشتر کتابخانههای JS از دست میدهند، چون همه از Number میگذرند)؛
۳. دامنه پشتیبانی BOM، کامنت و ویرگول انتهایی.
اگر مستنداتی نیست، یک نمونه کوچک بنویسید و خودتان آزمون کنید. این مطمئنتر از خواندن README است.
۳.۴ وضعیت نگهداری
خطر یک کتابخانه JSON نبود قابلیت نیست، بلکه غفلت بلندمدت است: دیگر کسی وصله امنیتی (آلودگی prototype، ReDoS) منتشر نمیکند.
۴. مقایسه با زبانهای دیگر
| زبان | کتابخانه استاندارد / جریان اصلی | تفاوت کلیدی |
|---|---|---|
| JavaScript | JSON.parse |
همه عددها دقت مضاعف دارند |
| TypeScript | همان بالا + jsonc-parser / zod |
نوعها فقط در زمان کامپایل وجود دارند |
| Go | encoding/json |
پیشفرض float64، برای حفظ دقت از UseNumber() استفاده کنید؛ json.RawMessage برای تجزیه معوق |
| Java | Jackson / Gson / Moshi | با Jackson مراقب خطر فعالسازی default typing باشید |
| Python | json / orjson |
parse_float=Decimal دقت را حفظ میکند؛ orjson سریعتر است اما همه نوعها را پشتیبانی نمیکند |
| Rust | serde_json |
تجزیه معکوس قویتایپ؛ قابلیت arbitrary_precision دقت را حفظ میکند |
| C++ | simdjson / RapidJSON | simdjson توان عبوری تجزیه را هدف میگیرد، RapidJSON عمومیتر است |
هنگام تبادل داده میان زبانها، آسانترین چیزهایی که باعث لغزش میشوند همچنان دقت عدد و قالب زماناند؛ انتخاب کتابخانه فقط میتواند آنها را کاهش دهد نه حذف کند.
۵. ترکیبهای معمول
گزینه ۱: سایت ابزار (سمت مرورگر)
Parsing and error location: jsonc-parser
Editor: CodeMirror 6 + @codemirror/lang-json
Query: jsonpath-plus
Patch: fast-json-patch
Share links: lz-string
ویژگی تعیینکننده این ترکیب این است که همه چیز محلی اجرا میشود و هیچ دادهای بارگذاری نمیشود، که با انتظار حریم خصوصی یک سایت ابزاری میخواند.
گزینه ۲: gateway API سمت سرور
Validation: Ajv (compile the schema once, reuse it)
Parsing: native JSON.parse (together with a body size limit)
Deferred parsing of large fields: keep the raw string, parse only when needed
کتابخانههای پرسوجو/patch را به لایه gateway نیاورید تا منطق کسبوکار پیاده کنید — آن کار لایه کسبوکار است.
گزینه ۳: CLI و اسکریپتها
Pick fields: jq
Format conversion: yq / dasel
Interactive browsing: jless
Batch validation: ajv-cli
۶. تأثیر واقعی اندازه بسته و عملکرد
jsonc-parserبسیار کوچک است و برای بسته اصلی مناسب است؛json5کمی بزرگتر ازjsonc-parserاست چون نحو بیشتری پشتیبانی میکند؛jsonpath-plusارزیابی عبارت را در خود دارد و بهطور محسوس بزرگتر است، پس باید صفحهبهصفحه بارگذاری تنبل شود؛fast-json-patchاندازه متوسط دارد و فقط وقتی به قابلیت مقایسه نیاز دارید لازم است.
بهینهسازی سرراست است: در هر صفحه بهصورت پویا import کنید و آنها را در بسته صفحه اول نگذارید.
const { JSONPath } = await import('jsonpath-plus');
۷. چکلیست
- [ ] کتابخانهها بر اساس هدف انتخاب میشوند؛ از کتابخانه پرسوجو برای تجزیه استفاده نکنید؛
- [ ] وقتی به مکان خطای دقیق نیاز دارید از
jsonc-parserاستفاده میشود؛ - [ ] وقتی کامنتها و قالببندی باید حفظ شوند از APIهای ویرایشی استفاده میشود؛
- [ ] سه رفتار مرزی در عمل آزمون میشوند: کلید تکراری، عددهای صحیح بزرگ و BOM؛
- [ ] وضعیت نگهداری کتابخانه و اعلامیههای امنیتی زیر نظر گرفته میشود؛
- [ ] کتابخانههای بزرگ بهصورت موردی پویا import میشوند.
پرسشهای متداول
چگونه برای اندازه پروژهام کتابخانه JSON انتخاب کنم؟
ابزارهای کوچکی که فقط داده API میخوانند میتوانند روی JSON.parse بومی بمانند. پروژههایی که به مکان خطای در حد ویرایشگر نیاز دارند یا باید قالب اصلی را حفظ کنند باید از jsonc-parser استفاده کنند. gateway سمت سرور فقط به اعتبارسنجی و تجزیه نیاز دارد و کتابخانههای پرسوجو و patch را به لایه کسبوکار واگذار میکند، در حالی که اسکریپتهای CLI میتوانند مستقیم از jq، yq و ajv-cli استفاده کنند.
چرا وضعیت نگهداری از تعداد قابلیت مهمتر است؟
خطر واقعی یک کتابخانه JSON غفلت بلندمدت است، نه نبود قابلیت: دیگر کسی وصله امنیتی برای آلودگی prototype یا ReDoS منتشر نمیکند. هرقدر فهرست قابلیتها کامل باشد، کتابخانه رهاشده شما را وادار به وصله زدن خودتان میکند. نگهداری و اعلامیههای امنیتی را معیار سخت بدانید نه اینکه جدول قابلیتها را مقایسه کنید.
آیا از JSON.parse استفاده کنم تا یک فیلد را تغییر دهم و کامنت و تورفتگی را حفظ کنم؟
نه. تجزیه، تغییر object و سپس سریالسازی، کامنتها، ترتیب کلیدها، سبک تورفتگی، نگارش لیترال عددی (1e3 به 1000 تبدیل میشود) و شکلهای escape (\u4e2d به کاراکتر واقعی تبدیل میشود) را از دست میدهد. تغییر یک فیلد با حفظ بقیه به API ویرایشی مانند modify و applyEdits در jsonc-parser نیاز دارد.