وقتی یک فایل YAML را میخوانیم، فقط با مجموعهای از کلمات و عددها روبهرو نیستیم؛ هر مقدار یک نوع داده دارد و Parser بر اساس قواعد YAML تصمیم میگیرد آن مقدار رشته، عدد، مقدار منطقی، null، تاریخ، فهرست یا نگاشت است. این تشخیص مستقیم روی رفتار برنامه اثر میگذارد. برای مثال مقدار false با رشته "false" یکسان نیست، عدد 8080 با رشته "8080" تفاوت دارد و مقدار خالی پس از دونقطه ممکن است بهصورت null تفسیر شود. در این راهنما انواع داده در YAML را با مثالهای صحیح و اشتباه، تفاوت نسخهها و Parserها، روش کنترل نوع و نکات کاربردی بررسی میکنیم.
پاسخ سریع: انواع داده اصلی در YAML شامل Scalarها مانند String، Number، Boolean و null، ساختارهای Collection مانند Sequence و Mapping، و در برخی Parserها نوعهای تکمیلی مانند Timestamp است. برای جلوگیری از تبدیل ناخواسته، مقدارهای مبهم را داخل نقلقول قرار دهید و پس از Parse، نوع و محدوده داده را در برنامه یا با Schema بررسی کنید.
نوع داده در YAML چیست؟
نوع داده مشخص میکند یک مقدار چگونه تفسیر، ذخیره و پردازش شود. متن YAML در نهایت توسط Parser به ساختارهای زبان مقصد تبدیل میشود؛ مثلاً یک Mapping ممکن است به Object یا Dictionary، یک Sequence به Array یا List و یک Scalar عددی به نوع عددی زبان تبدیل شود. بنابراین ظاهر یک مقدار بهتنهایی کافی نیست؛ باید بدانیم Parser و Schema مورد استفاده چه برداشتی از آن دارند.
YAML برخلاف JSON فقط به شش نوع پایه محدود نیست و سیستم Tag و Schema انعطاف بیشتری ایجاد میکند. همین انعطاف میتواند مفید یا خطرناک باشد. یک فایل ممکن است در دو کتابخانه مختلف کمی متفاوت تفسیر شود، بهویژه وقتی مقدارهایی مانند تاریخ، Booleanهای قدیمی، اعداد خاص یا Tagهای سفارشی در آن وجود داشته باشد.
دستهبندی اصلی انواع داده در YAML
| دسته | نوعهای رایج | نمونه | خروجی معمول پس از Parse |
|---|---|---|---|
| Scalar | String، Number، Boolean، null | port: 8080 | یک مقدار منفرد |
| Sequence | List / Array | tags: [api, yaml] | آرایه یا فهرست |
| Mapping | Object / Dictionary | server: {host: localhost} | شیء یا نگاشت کلید-مقدار |
| نوعهای وابسته به Schema | Timestamp و Tagهای خاص | releasedAt: 2026-08-07 | رشته، Date یا نوع کتابخانهای |
String در YAML
رشته رایجترین نوع Scalar است. YAML اجازه میدهد بسیاری از رشتهها بدون نقلقول نوشته شوند، اما هر رشته بدون نقلقول امن نیست. اگر مقدار شبیه عدد، Boolean، null، تاریخ یا بخشی از Syntax باشد، Parser ممکن است آن را به نوع دیگری تبدیل کند.
رشته ساده بدون نقلقول
name: xDFlow
message: ابزارهای آنلاین برای توسعهدهندگان
framework: Next.js
این شکل برای متنهای ساده و بدون ابهام خواناست. بااینحال وجود کاراکترهایی مثل #، ترکیب دونقطه و فاصله، فاصله ابتدایی یا مقدارهای خاص میتواند معنا را تغییر دهد.
رشته با نقلقول تکی
code: '00125'
booleanText: 'false'
message: 'Don''t change the type'
در رشته تکنقلقولی، بیشتر کاراکترها بهصورت literal نگه داشته میشوند. برای قرار دادن خود علامت نقلقول تکی، آن را دو بار مینویسیم. این روش برای مسیرها، Regexهای ساده و متنهایی که نباید Escape Sequence پردازش کنند مناسب است.
رشته با نقلقول دوتایی
title: "YAML data types"
line: "first\nsecond"
unicode: "Persian: \u0641\u0627\u0631\u0633\u06cc"
رشته دوتایی Escape Sequenceهایی مانند
، و Unicode Escape را تفسیر میکند. اگر Backslash باید دقیقاً حفظ شود، باید آن را Escape کنید یا از نقلقول تکی استفاده کنید.
نمونه مبهم: رشته یا عدد؟
postalCodeWrong: 00125
postalCodeCorrect: "00125"
versionWrong: 1.20
versionCorrect: "1.20"
کد پستی، شماره تلفن، شناسه، نسخه و شماره سفارش معمولاً مفهوم عددی ندارند، حتی اگر فقط از رقم تشکیل شده باشند. آنها را رشته بنویسید تا صفر ابتدایی، قالب و دقت حفظ شود.
Number در YAML
YAML میتواند عدد صحیح و اعشاری را نمایش دهد. پشتیبانی دقیق از برخی قالبها به نسخه YAML و کتابخانه بستگی دارد؛ بنابراین برای داده قابلانتقال، از قالبهای روشن و کمابهام استفاده کنید.
عدد صحیح
port: 8080
retryCount: 3
offset: -12
zero: 0
عدد اعشاری و نماد علمی
ratio: 0.75
temperature: -3.5
largeValue: 6.02e23
smallValue: 1.5e-6
پس از Parse، محدودیتهای زبان مقصد اهمیت دارد. بعضی Runtimeها همه اعداد را با نوع ممیز شناور نگه میدارند، برخی بین Integer و Float تفاوت میگذارند و برخی برای عددهای بسیار بزرگ به نوعهای ویژه نیاز دارند. YAML معتبر تضمین نمیکند که عدد در نوع مقصد بدون کاهش دقت ذخیره شود.
اعداد خاص و قابلیت حمل
قالبهایی مانند hexadecimal، octal، infinity و NaN ممکن است توسط Schemaها یا Parserهای مختلف به شکل یکسان پشتیبانی نشوند. برای فایل تنظیماتی که میان چند زبان جابهجا میشود، بهتر است از عدد دهدهی معمولی استفاده کنید یا مقدار خاص را صریحاً به رشته تبدیل کنید.
hexValue: 0xFF
portableHexText: "0xFF"
notANumberText: "NaN"
Boolean در YAML
مقدار منطقی دو حالت true و false دارد. در YAML مدرن، نوشتن true و false روشنترین انتخاب است. برخی Parserهای قدیمی یا Schemaهای سازگار با YAML 1.1 ممکن است واژههایی مانند yes، no، on و off را نیز Boolean بدانند، در حالی که Parserهای مبتنی بر YAML 1.2 معمولاً آنها را رشته در نظر میگیرند.
enabled: true
cache: false
answerText: "yes"
switchText: "off"
برای سازگاری میان ابزارها فقط از true و false استفاده کنید. هرجا واقعاً متن «yes» یا «off» مدنظر است، آن را Quote کنید.
اشتباه رایج در متغیرهای محیطی
# مقدار منطقی
featureEnabled: false
# رشتهای که شاید برنامه بعداً خودش Parse کند
FEATURE_ENABLED: "false"
بسیاری از سیستمهای متغیر محیطی در نهایت فقط رشته تحویل میدهند. برنامه باید مشخص کند آیا ورودی YAML را مستقیماً Boolean میخواهد یا رشتهای که بعداً تبدیل میشود. مخلوط کردن این دو قرارداد باعث باگهایی میشود که در ظاهر فایل دیده نمیشوند.
null و مقدار خالی در YAML
null نبودن یک مقدار را نشان میدهد و با رشته خالی، عدد صفر، false یا کلید حذفشده یکسان نیست. شکل صریح null خواناتر و قابلفهمتر است.
middleName: null
legacyNull: ~
implicitNull:
emptyString: ""
zeroValue: 0
falseValue: false
| نمونه | معنا |
|---|---|
value: null | مقدار null صریح |
value: | معمولاً null ضمنی، اما برای خوانایی ضعیفتر |
value: "" | رشته خالی |
| نبودن کلید | ممکن است در منطق برنامه معنای متفاوتی داشته باشد |
در API و فایل تنظیمات باید قرارداد روشن باشد: آیا null یعنی «پاک کردن مقدار»، «استفاده از مقدار پیشفرض» یا «نامشخص»؟ این موضوع با Syntax حل نمیشود و به اعتبارسنجی معنایی نیاز دارد.
Sequence یا Array در YAML
Sequence مجموعهای مرتب از اعضاست و معمولاً به Array یا List تبدیل میشود. اعضا میتوانند همنوع یا ناهمنوع باشند، اما برای دادههای قابلپیشبینی بهتر است ساختار اعضا یکسان باشد.
Block Sequence
languages:
- JavaScript
- TypeScript
- Python
Flow Sequence
ports: [80, 443, 8080]
Block Style برای فهرستهای طولانی و تودرتو خواناتر است. Flow Style برای فهرستهای کوتاه مناسب است، اما استفاده زیاد از آن YAML را شبیه JSON فشرده و نگهداری آن را دشوار میکند.
فهرست Objectها
services:
- name: api
port: 8080
enabled: true
- name: worker
port: 8090
enabled: false
در این نمونه هر عضو Sequence یک Mapping است. تراز بودن کلیدهای هر عضو مهم است؛ یک فاصله اشتباه میتواند کلید را به سطح دیگری منتقل کند.
Mapping یا Object در YAML
Mapping مجموعهای از زوجهای کلید و مقدار است. در بسیاری از زبانها به Object، Dictionary، Map یا Hash تبدیل میشود. کلیدها باید در محدوده همان Mapping یکتا باشند؛ هرچند بعضی Parserها کلید تکراری را بیصدا میپذیرند و مقدار آخر را جایگزین میکنند.
server:
host: localhost
port: 8080
tls:
enabled: true
certificatePath: "/etc/certs/app.pem"
کلید تکراری؛ YAML ظاهراً خوانا اما خطرناک
server:
port: 8080
port: 9090
این فایل نباید بهعنوان تنظیمات قابلاعتماد پذیرفته شود. بسته به Parser ممکن است خطا بگیرید یا فقط مقدار 9090 باقی بماند. Validator را طوری تنظیم کنید که کلید تکراری را رد کند.
Timestamp و تاریخ در YAML
برخی Schemaهای YAML مقدارهایی شبیه تاریخ و زمان را به Timestamp تبدیل میکنند. کتابخانهای دیگر ممکن است همان مقدار را رشته نگه دارد. اگر برنامه شما نوع Date واقعی میخواهد، رفتار کتابخانه را بررسی کنید؛ اگر فقط متن تاریخ لازم است، نقلقول بهترین راه جلوگیری از تبدیل ناخواسته است.
releaseDate: 2026-08-07
releaseDateText: "2026-08-07"
createdAt: 2026-08-07T10:30:00Z
createdAtText: "2026-08-07T10:30:00Z"
حتی پس از تبدیل به Date، موضوع منطقه زمانی، Offset و اعتبار تقویمی باقی میماند. Parse شدن Timestamp بهمعنای درست بودن آن برای منطق کسبوکار نیست.
Tagها و تعیین صریح نوع
YAML از Tag برای اعلام نوع یا معنای یک Node استفاده میکند. Tagهای استاندارد و Tagهای سفارشی وجود دارند، اما پشتیبانی و امنیت آنها میان کتابخانهها یکسان نیست. در فایلهای عمومی و ورودی کاربر، از Tag سفارشی بدون نیاز واقعی استفاده نکنید.
count: !!int "42"
text: !!str 42
flag: !!bool "true"
این نمونه قصد نوع را صریح میکند، ولی قابلیت حمل آن باید با Parser مقصد آزمایش شود. برای بسیاری از پروژهها Quote کردن رشته و اعتبارسنجی پس از Parse سادهتر و روشنتر است.
تشخیص ضمنی نوع چگونه باعث خطا میشود؟
Parser ابتدا متن را بر اساس Syntax به Nodeها تقسیم میکند، سپس Schema و Resolver تصمیم میگیرند Scalar چه نوعی داشته باشد. مشکل زمانی رخ میدهد که نویسنده یک رشته در ذهن دارد اما Resolver آن را عدد، Boolean یا تاریخ تشخیص میدهد.
accountId: 000742
status: on
release: 2026-08-07
price: 12.00
ممکن است صفرهای شناسه حذف شوند، status در برخی محیطها Boolean شود، release به Date تبدیل شود و price به عددی تبدیل شود که نمایش اعشار پایانی را حفظ نمیکند. نسخه کمابهام:
accountId: "000742"
status: "on"
release: "2026-08-07"
price: "12.00"
البته قیمت برای محاسبه بهتر است در مدل داده به کوچکترین واحد پولی و با نوع عدد صحیح ذخیره شود؛ رشته کردن صرفاً نمایش را حفظ میکند و جای طراحی درست مدل را نمیگیرد.
YAML 1.1 و YAML 1.2 چه تفاوتی در نوعها دارند؟
یکی از مهمترین منابع ناسازگاری، تفاوت Schemaهای رایج در نسخههای YAML است. YAML 1.1 مجموعه گستردهتری از شکلهای ضمنی Boolean و عدد را میپذیرفت. YAML 1.2 تلاش کرد رفتار را به JSON نزدیکتر و مقدارهای مبهم را کمتر کند. بااینحال نام نسخه روی فایل بهتنهایی تضمین نمیکند کتابخانه دقیقاً همان Schema را اجرا کند.
| مقدار | تفسیر محتمل در محیط قدیمی | انتخاب قابلحمل |
|---|---|---|
yes | Boolean true یا String | "yes" برای متن، true برای Boolean |
off | Boolean false یا String | "off" برای متن |
012 | عدد با تفسیر وابسته به Schema | "012" برای شناسه، 12 برای عدد |
2026-08-07 | Timestamp یا String | Quote در صورت نیاز به متن |
مثال واقعی: فایل تنظیمات یک سرویس
app:
name: "xdflow-api"
environment: "production"
debug: false
port: 8080
publicUrl: "example.invalid"
requestTimeoutSeconds: 30
allowedOrigins:
- "panel.example.invalid"
database:
host: "db.internal"
port: 5432
name: "xdflow"
username: "app_user"
passwordFromSecret: "DB_PASSWORD"
release:
version: "2.10"
date: "2026-08-07"
optionalFeature: null
در این ساختار، نام محیط، URL، نسخه، تاریخ و نام Secret عمداً رشته هستند. debug یک Boolean واقعی، port و timeout عدد، allowedOrigins یک Sequence، database و release دو Mapping و optionalFeature مقدار null است. چنین تفکیکی قرارداد داده را برای برنامه روشن میکند.
پیادهسازی و بررسی نوع در JavaScript
import YAML from "yaml";
const source = `
enabled: true
port: 8080
version: "2.10"
tags: [yaml, config]
optional: null
`;
const data = YAML.parse(source);
console.log(typeof data.enabled); // boolean
console.log(typeof data.port); // number
console.log(typeof data.version); // string
console.log(Array.isArray(data.tags)); // true
console.log(data.optional === null); // true
پس از Parse فقط به موفق بودن عملیات اکتفا نکنید. شکل Object، نوع فیلدها، محدوده عددها و کلیدهای مجاز را نیز بررسی کنید. داده Parseشده همچنان ورودی غیرقابلاعتماد است.
پیادهسازی و بررسی نوع در Python
import yaml
source = """
enabled: true
port: 8080
version: "2.10"
tags:
- yaml
- config
optional: null
"""
data = yaml.safe_load(source)
assert isinstance(data["enabled"], bool)
assert isinstance(data["port"], int)
assert isinstance(data["version"], str)
assert isinstance(data["tags"], list)
assert data["optional"] is None
برای داده غیرقابلاعتماد از Loader امن استفاده کنید. نام API دقیق به کتابخانه و نسخه آن بستگی دارد، اما اصل مهم این است که ساخت Objectهای دلخواه یا اجرای رفتارهای ناامن از طریق Tagها غیرفعال باشد.
تفاوت Syntax Validation، Type Validation و Schema Validation
| نوع بررسی | پرسش اصلی | نمونه خطا |
|---|---|---|
| Syntax Validation | آیا YAML قابل Parse است؟ | تورفتگی خراب یا کوتیشن بستهنشده |
| Type Validation | آیا نوع مقدار درست است؟ | port بهصورت String بهجای Number |
| Schema Validation | آیا ساختار و محدودیتها رعایت شدهاند؟ | نبودن کلید host یا port خارج از محدوده |
| Semantic Validation | آیا مقدار در منطق سیستم معنی دارد؟ | تاریخ پایان قبل از تاریخ شروع |
ابزار Formatter فقط ظاهر را خواناتر میکند. Validator نحوی خطاهای Parse را پیدا میکند. برای تضمین قرارداد واقعی داده، Schema و قواعد معنایی لازم است.
خطاهای رایج مربوط به انواع داده در YAML
۱. نوشتن شناسه بهصورت Number
شناسهای مثل شماره سفارش یا کد پستی برای محاسبه نیست. آن را String نگه دارید تا صفر ابتدایی و قالب از بین نرود.
۲. استفاده از yes و no بهجای true و false
این مقادیر میان Schemaها مبهماند. برای Boolean از true و false و برای متن از نقلقول استفاده کنید.
۳. برابر دانستن null و رشته خالی
null نبود مقدار را نشان میدهد، اما رشته خالی یک مقدار موجود با طول صفر است. برنامه باید این دو را جداگانه مدیریت کند.
۴. اعتماد به نوع خودکار تاریخ
تبدیل تاریخ ممکن است میان Parserها فرق کند. قرارداد را مشخص و در صورت نیاز تاریخ را String نگه دارید و در لایه برنامه Parse کنید.
۵. مخلوط کردن نوع اعضای یک فهرست
ports:
- 80
- "443"
- null
YAML این ساختار را ممکن میداند، اما برنامه مصرفکننده ممکن است انتظار فهرست عددی داشته باشد. Schema باید همنوع بودن اعضا را کنترل کند.
۶. نادیده گرفتن دقت عددی
عددهای بسیار بزرگ، مقادیر پولی و اعشار حساس ممکن است در Float دقت خود را از دست بدهند. نوع مقصد و روش ذخیرهسازی را آگاهانه انتخاب کنید.
راهنمای عیبیابی وقتی نوع اشتباه Parse میشود
- مقدار مشکلدار را به کوچکترین فایل YAML مستقل تبدیل کنید.
- خروجی Parse و نوع Runtime را چاپ کنید، نه فقط مقدار نمایشدادهشده را.
- نسخه کتابخانه، نسخه YAML و Schema فعال را بررسی کنید.
- مقدار را Quote کنید و نتیجه را دوباره آزمایش کنید.
- Tagهای سفارشی و Resolverهای اضافه را موقتاً غیرفعال کنید.
- با Parser واقعی محیط تولید تست بگیرید؛ نتیجه ابزار دیگری الزاماً یکسان نیست.
- پس از Parse، Schema Validation و تست واحد اضافه کنید.
نکات امنیتی انواع داده و Parser YAML
مشکل نوع فقط یک مسئله کیفیت داده نیست. Tagهای ناامن، Aliasهای بسیار زیاد، ساختارهای عمیق و ورودیهای بزرگ میتوانند برای مصرف منابع یا ساخت Objectهای ناخواسته استفاده شوند. برای ورودی کاربر Loader امن، محدودیت حجم، عمق و تعداد Alias، Timeout و Schema محدودکننده در نظر بگیرید.
- ورودی YAML را مانند هر ورودی خارجی غیرقابلاعتماد فرض کنید.
- ساخت نوعهای دلخواه و اجرای Constructorهای سفارشی را غیرفعال کنید.
- کلیدهای ناشناخته و کلیدهای تکراری را رد کنید.
- نوع، طول رشته، بازه عدد و تعداد اعضای Collection را محدود کنید.
- Secret را داخل فایل عمومی یا Repository قرار ندهید؛ فقط نام مرجع Secret را ذخیره کنید.
نکات عملکرد برای YAMLهای بزرگ
فایل YAML بزرگ با Nodeهای عمیق، Aliasهای زیاد و Collectionهای عظیم میتواند حافظه و زمان Parse را افزایش دهد. برای داده حجیم، YAML همیشه بهترین فرمت تبادل نیست. فایل را به بخشهای کوچکتر تقسیم کنید، از تکرار غیرضروری جلوگیری کنید، محدودیت منابع بگذارید و در مسیرهای پرترافیک نتیجه Parse و Validation را بیدلیل تکرار نکنید.
Anchor و Alias میتوانند تکرار متن را کم کنند، اما پس از Resolve شدن ممکن است ساختار منطقی بزرگی ایجاد شود. معیار حجم فایل خام بهتنهایی برای تخمین حافظه کافی نیست.
بهترین روشها برای کنترل انواع داده در YAML
- Boolean را فقط با true و false بنویسید.
- شناسه، کد پستی، نسخه، شماره تلفن و مقدارهای دارای صفر ابتدایی را Quote کنید.
- برای null از شکل صریح
nullاستفاده کنید. - تاریخ و زمان را با قرارداد مشخص و در صورت نیاز داخل نقلقول نگه دارید.
- در یک Sequence تا حد ممکن اعضای همساختار قرار دهید.
- کلید تکراری را خطا در نظر بگیرید.
- بعد از Parse، Schema و اعتبارسنجی معنایی اجرا کنید.
- رفتار Parser محیط توسعه و تولید را یکسان و نسخه آن را قفل کنید.
- برای ورودی غیرقابلاعتماد از Safe Loader و محدودیت منابع استفاده کنید.
چکلیست بررسی نوع داده در فایل YAML
- آیا همه شناسهها و نسخهها String هستند؟
- آیا Booleanها فقط true یا false نوشته شدهاند؟
- آیا تفاوت null، رشته خالی و کلید حذفشده روشن است؟
- آیا عددها در محدوده و دقت نوع مقصد قرار میگیرند؟
- آیا تاریخها عمداً String یا Timestamp هستند؟
- آیا اعضای List ساختار مورد انتظار را دارند؟
- آیا Mapping کلید تکراری یا ناشناخته ندارد؟
- آیا فایل با Parser واقعی پروژه آزمایش شده است؟
- آیا Schema Validation پس از Parse اجرا میشود؟
- آیا Loader امن و محدودیت منابع فعال است؟
جمعبندی
انواع داده در YAML فقط یک موضوع نظری نیستند؛ نوعی که Parser انتخاب میکند مستقیماً رفتار برنامه را تعیین میکند. String، Number، Boolean، null، Sequence و Mapping پایههای اصلیاند و نوعهایی مانند Timestamp یا Tagهای سفارشی به Schema و کتابخانه وابستهاند. برای فایلهای قابلحمل، مقدارهای مبهم را Quote کنید، از true و false صریح استفاده کنید، null را از رشته خالی جدا بدانید و بعد از Parse حتماً نوع، ساختار و منطق داده را اعتبارسنجی کنید. برای مشاهده ساختار و بررسی سریع فایل میتوانید از YAML Studio و برای تشخیص خطاهای نحوی از YAML Validator استفاده کنید.