در YAML، فهرست یا Array یکی از مهمترین ساختارها برای نگهداری چند مقدار مرتبط است. هرجا لازم باشد مجموعهای از نامها، پورتها، مرحلههای یک Pipeline، سرویسهای یک پروژه یا چند شیء همنوع را کنار هم قرار دهید، معمولاً از YAML List استفاده میکنید. ظاهر ساده این ساختار ممکن است گمراهکننده باشد؛ زیرا بخش بزرگی از خطاهای واقعی YAML از تورفتگی نادرست، ترکیب اشتباه List و Mapping، یا برداشت متفاوت Parser از مقدارهای کوتاهشده ناشی میشود.
پاسخ سریع: YAML Array یا YAML List مجموعهای مرتب از آیتمهاست. در شیوه Block، هر آیتم با خط تیره و فاصله آغاز میشود؛ مانند
- api. در شیوه Flow نیز میتوان همان فهرست را داخل براکت نوشت؛ مانند[api, worker, scheduler]. آیتمها میتوانند Scalar، Object، List تودرتو یا ترکیبی از آنها باشند، اما تورفتگی باید دقیق و سازگار باقی بماند.
YAML Array چیست؟
در اصطلاح استاندارد YAML، ساختاری که در بسیاری از زبانهای برنامهنویسی Array یا List نامیده میشود، Sequence است. Sequence مجموعهای مرتب از Nodeهاست؛ بنابراین ترتیب آیتمها بخشی از داده محسوب میشود. اگر اولین آیتم یک فهرست «development» و دومین آیتم «production» باشد، جابهجایی آنها ممکن است معنای پیکربندی را تغییر دهد.
هر آیتم در Sequence میتواند یک مقدار ساده مثل String و Number، یک Mapping شبیه Object، یا حتی Sequence دیگری باشد. همین انعطاف باعث میشود YAML برای فایلهای تنظیمات، گردشکارهای CI/CD، تعریف Containerها، فهرست دسترسیها و دادههای ساختیافته خوانا باشد.
environments:
- development
- staging
- production
در این مثال، کلید environments به یک Sequence سهعضوی اشاره میکند. ترتیب اعضا همان ترتیبی است که در فایل نوشته شده است.
Syntax اصلی List در YAML
Block Sequence با خط تیره
رایجترین روش نوشتن فهرست در YAML، Block Style است. هر آیتم در یک خط جدا قرار میگیرد و با نویسه - و سپس حداقل یک فاصله آغاز میشود.
languages:
- Python
- JavaScript
- Go
فاصله بعد از خط تیره مهم است. عبارت -Python آیتم استاندارد یک Sequence نیست؛ Parser آن را متناسب با محل و نسخه YAML ممکن است به شکل دیگری تفسیر کند یا خطا بدهد. فرم روشن و قابل نگهداری همیشه - Python است.
Flow Sequence با براکت
YAML اجازه میدهد فهرستهای کوتاه را شبیه JSON داخل براکت بنویسید. آیتمها با ویرگول جدا میشوند.
languages: [Python, JavaScript, Go]
Block و Flow از نظر مدل داده یک Sequence میسازند، اما Block برای فهرستهای طولانی و پیچیده خواناتر است. Flow برای فهرستهای کوتاه، مختصات، Tagهای کمتعداد یا مقدارهایی که قرار است در یک خط دیده شوند مناسبتر است.
تفاوت YAML List با Array در زبانهای برنامهنویسی
| ویژگی | YAML Sequence | Array در برنامهنویسی |
|---|---|---|
| ماهیت | نمایش متنی داده | ساختار داده در حافظه Runtime |
| نوع آیتمها | میتواند ترکیبی باشد | وابسته به زبان؛ گاهی همنوع و گاهی ترکیبی |
| ترتیب | حفظ میشود | معمولاً حفظ میشود |
| اندیس | در متن YAML نوشته نمیشود | معمولاً با اندیس عددی قابل دسترسی است |
| اعتبارسنجی نوع | به Parser یا Schema وابسته است | به سیستم نوع زبان وابسته است |
پس YAML Array خودش یک آرایه اجرایی نیست. Parser پس از خواندن فایل، Sequence را به List، Array، Slice یا ساختار مشابه در زبان مقصد تبدیل میکند.
فهرست مقادیر ساده
سادهترین حالت، فهرستی از Scalarهاست. Scalar میتواند String، Number، Boolean، null، تاریخ یا نوع دیگری باشد که Parser پشتیبانی میکند.
ports:
- 80
- 443
- 8080
features:
- true
- false
- null
از نظر نحوی، YAML اجازه ترکیب نوعها را میدهد، اما از نظر طراحی داده بهتر است یک List مفهومی تا جای ممکن اعضای هممعنا داشته باشد. فهرستی که هم پورت عددی، هم نام کاربر و هم Object تنظیمات را در یک سطح نگه میدارد، معمولاً خوانایی و اعتبارسنجی ضعیفی خواهد داشت.
فهرست Objectها یا Mappingها
یکی از کاربردهای اصلی YAML، ساخت فهرستی از Objectهاست. در این حالت هر آیتم با خط تیره شروع میشود و سپس کلیدهای آن Mapping زیر همان آیتم قرار میگیرند.
services:
- name: api
port: 8080
enabled: true
- name: worker
port: 9090
enabled: false
خط تیره آغازگر یک آیتم جدید است. کلیدهای port و enabled باید همتراز با name در همان Mapping باشند. اگر یکی از این کلیدها بیش از حد عقب یا جلو رود، ممکن است عضو Object دیگری شود یا Parser خطای تورفتگی بدهد.
فرم طولانیتر و شفافتر
میتوان خط تیره را در یک خط و Mapping را در خطوط بعدی نوشت، اما فرم فشرده بالا رایجتر و خواناتر است.
services:
-
name: api
port: 8080
-
name: worker
port: 9090
هر دو فرم معتبرند؛ با این حال در پروژههای تیمی بهتر است یک Style ثابت انتخاب شود تا Diffها کوچک و بازبینی ساده بماند.
List تودرتو در YAML
یک Sequence میتواند Sequence دیگری را درون خود نگه دارد. این ساختار برای ماتریسها، گروهبندی مرحلهها یا دستهبندی چندسطحی کاربرد دارد.
matrix:
- [1, 2, 3]
- [4, 5, 6]
- [7, 8, 9]
همان داده را میتوان کاملاً به شکل Block نوشت:
matrix:
-
- 1
- 2
- 3
-
- 4
- 5
- 6
در Listهای تودرتو، فاصله هر سطح باید واضح باشد. استفاده از دو فاصله برای هر سطح یک قرارداد رایج است، هرچند خود YAML الزام عمومی به دقیقاً دو فاصله ندارد. مهم، سازگاری در کل فایل و استفاده نکردن از Tab است.
ترکیب List و Mapping
ساختارهای واقعی معمولاً ترکیبیاند. برای مثال هر محیط میتواند نام، متغیرها و فهرستی از Regionها داشته باشد.
deployments:
- environment: staging
regions:
- eu-west
- us-east
variables:
LOG_LEVEL: debug
CACHE_ENABLED: false
- environment: production
regions:
- eu-central
variables:
LOG_LEVEL: warning
CACHE_ENABLED: true
در این مثال، deployments یک List از Mappingهاست؛ regions در هر Mapping یک List است و variables یک Mapping دیگر. برای فهم درست چنین ساختاری، به رابطه عمودی کلیدها و سطح تورفتگی آنها نگاه کنید، نه فقط به خط تیرهها.
مثال واقعی: تعریف مراحل یک Pipeline
pipeline:
name: release
stages:
- name: test
commands:
- npm ci
- npm run lint
- npm test
- name: build
commands:
- npm run build
artifacts:
- dist/
- reports/
- name: deploy
when: production
commands:
- ./deploy.sh
کلید stages یک Sequence از مرحلههاست. هر مرحله یک Mapping و کلید commands درون آن یک Sequence از دستورهاست. ترتیب commandها اهمیت دارد؛ زیرا اجراکننده معمولاً آنها را به همان ترتیب پردازش میکند. این مثال نشان میدهد که Sequence صرفاً مجموعهای بدون ترتیب نیست.
مثال صحیح و غلط YAML Array
مثال صحیح
users:
- name: Sara
roles:
- editor
- reviewer
- name: Ali
roles:
- viewer
مثال غلط: تورفتگی نامنظم
users:
- name: Sara
roles:
- editor
کلید roles یک فاصله اضافه دارد و همتراز با name نیست. این خطا ممکن است با پیامهایی مانند «mapping values are not allowed here» یا «bad indentation» ظاهر شود.
مثال غلط: فراموشکردن خط تیره
users:
name: Sara
name: Ali
این ساختار List نیست؛ یک Mapping با کلید تکراری name است. بعضی Parserها کلید دوم را جایگزین اول میکنند و بعضی Validatorها آن را خطا میدانند. برای دو کاربر باید هر Mapping با خط تیره آغاز شود.
آیتمهای چندخطی در List
هر عضو فهرست میتواند متن چندخطی باشد. علامت | شکست خطها را حفظ میکند و علامت > معمولاً خطوط را به متن پیوسته تبدیل میکند.
messages:
- |
خط اول پیام
خط دوم پیام
- >
این متن در چند خط نوشته شده
اما معمولاً به صورت یک پاراگراف خوانده میشود.
تورفتگی متن باید از سطح خط تیره بیشتر باشد. اگر متن همسطح آیتم بعدی قرار گیرد، Parser پایان Scalar چندخطی را تشخیص میدهد و ساختار ممکن است برخلاف انتظار تغییر کند.
فهرست خالی و مقدار null
فهرست خالی با [] نمایش داده میشود. این مقدار با null یا نبودن کلید یکسان نیست.
allowed_ips: []
blocked_ips: null
| مقدار | معنا |
|---|---|
[] | List وجود دارد اما هیچ عضوی ندارد |
null | مقدار مشخص نشده یا تهی است |
| نبودن کلید | فیلد اصلاً در سند ارسال نشده است |
این تفاوت در APIها، Merge تنظیمات و اعتبارسنجی Schema مهم است. List خالی ممکن است به معنی «همه مقدارهای قبلی را پاک کن» باشد، در حالی که نبودن کلید میتواند به معنی «تغییری نده» تفسیر شود.
دسترسی به آیتمهای YAML List پس از Parse
YAML فقط قالب Serialization است. بعد از Parse، دسترسی به اعضا با قواعد زبان مقصد انجام میشود.
JavaScript
const config = parseYaml(source);
console.log(config.services[0].name);
console.log(config.services.map(service => service.port));
Python
config = parse_yaml(source)
print(config["services"][0]["name"])
ports = [service["port"] for service in config["services"]]
نام تابع Parse به کتابخانه وابسته است. نکته اصلی این است که Sequence معمولاً به Array یا List و Mapping به Object یا Dictionary تبدیل میشود.
نوعهای ترکیبی؛ معتبر اما پرریسک
items:
- 42
- hello
- true
- name: api
- [1, 2]
این YAML از نظر ساختاری میتواند معتبر باشد، اما پردازش آن دشوار است؛ زیرا مصرفکننده باید برای هر عضو نوع جداگانهای بررسی کند. اعتبار نحوی با طراحی خوب داده یکسان نیست. بهتر است اعضای یک List قرارداد قابل پیشبینی داشته باشند، بهخصوص زمانی که فایل توسط چند سرویس یا زبان خوانده میشود.
خطاهای رایج YAML Array
استفاده از Tab برای تورفتگی
در YAML برای تورفتگی از Space استفاده کنید. Tab میتواند باعث خطای Parse یا تفاوت رفتار میان ابزارها شود. Editor را طوری تنظیم کنید که Tab را به دو یا چهار Space تبدیل کند.
ناهمترازی خط تیرهها
servers:
- api
- worker
دو خط تیره باید در یک ستون باشند؛ زیرا عضوهای یک Sequence در یک سطح قرار دارند.
جاگذاشتن ویرگول در Flow Style
ports: [80, 443 8080]
در Flow Sequence جداکننده ویرگول ضروری است.
ترکیب Block و Flow به شکل مبهم
ترکیب Styleها مجاز است، اما زیادهروی در آن خوانایی را کاهش میدهد. برای ساختارهای پیچیده Block Style را ترجیح دهید.
کلید تکراری داخل Objectهای List
services:
- name: api
port: 80
port: 8080
این مشکل مربوط به Mapping داخل List است. حتی اگر Parser آخرین مقدار را نگه دارد، فایل قابل اتکا نیست و باید کلید تکراری حذف شود.
Troubleshooting؛ چگونه خطای List را پیدا کنیم؟
- از خط گزارششده یک یا دو خط بالاتر را هم بررسی کنید. خطای تورفتگی معمولاً در نقطهای ظاهر میشود که Parser دیگر قادر به ادامه نیست، نه لزوماً محل شروع اشتباه.
- نمایش Whitespace را در Editor فعال کنید. Tab و Space اضافی با چشم معمولی دیده نمیشوند.
- ساختار پیچیده را کوچک کنید. List تودرتو را موقتاً به دو یا سه آیتم کاهش دهید تا سطح مشکل مشخص شود.
- فایل را با YAML Validator بررسی کنید. Formatter ممکن است فقط YAML قابل Parse را مرتب کند و جای Schema Validation را نمیگیرد.
- نوع واقعی خروجی Parser را ببینید. گاهی مقدارهایی مانند تاریخ، Boolean یا Number برخلاف انتظار به نوع دیگری تبدیل میشوند.
- List خالی، null و نبود کلید را جداگانه تست کنید. برنامه مقصد ممکن است برای هرکدام رفتار متفاوتی داشته باشد.
بهترین روشها برای YAML List
- برای هر سطح تورفتگی یک اندازه ثابت، ترجیحاً دو Space، انتخاب کنید.
- برای فهرستهای چندعضوی یا Objectهای پیچیده از Block Style استفاده کنید.
- اعضای یک List را از نظر ساختار و معنا تا جای ممکن همسان نگه دارید.
- برای Objectهای تکرارشونده، مجموعه کلیدهای اصلی را ثابت نگه دارید.
- مقدارهای مبهم مانند
yes،onیا تاریخها را در صورت نیاز Quote کنید تا رفتار Parser روشن باشد. - فهرستهای طولانی را بر اساس منطق دامنه مرتب کنید، نه صرفاً زیبایی ظاهری.
- قبل از Commit، فایل را Parse و در صورت وجود قرارداد داده، با Schema معتبر کنید.
- از Comment برای توضیح دلیل ترتیب آیتمها استفاده کنید، نه توضیح واضحات Syntax.
نکات عملکرد و نگهداری
Parserهای YAML معمولاً کل سند را به ساختار حافظه تبدیل میکنند. Listهای بسیار بزرگ میتوانند زمان Parse و مصرف حافظه را افزایش دهند. برای دادههای عظیم، YAML همیشه بهترین انتخاب نیست؛ بهخصوص وقتی فایل بیشتر نقش انتقال داده دارد تا پیکربندی انسانی. در چنین شرایطی قالبهای Stream-friendly یا پایگاه داده ممکن است مناسبتر باشند.
در فایلهای تنظیمات نیز Listهای چندصدعضوی نگهداری دشواری دارند. تقسیم منطقی فایل، تولید خودکار بخشهای تکراری و Validation در CI میتواند خطای انسانی را کم کند. Anchor و Alias گاهی تکرار را کاهش میدهند، اما استفاده افراطی از آنها فهم جریان داده را سخت میکند.
نکات امنیتی
خود YAML List رمزنگاری یا مکانیزم امنیتی نیست. هرگز Secret، Token یا Password را فقط به دلیل قرارگرفتن در فایل YAML امن فرض نکنید. فایلهای پیکربندی باید سطح دسترسی مناسب داشته باشند و Secretها ترجیحاً از Secret Manager یا متغیرهای محیطی امن دریافت شوند.
همچنین فایل YAML ناشناس را با Loader ناامن پردازش نکنید. بعضی پیادهسازیها قابلیت ساخت Objectهای خاص یا Tagهای سفارشی دارند. برای ورودی غیرقابل اعتماد، Safe Loader و محدودیت اندازه، عمق تودرتو و تعداد Aliasها اهمیت دارد. معتبر بودن Syntax به معنی امن بودن محتوا نیست.
چکلیست بررسی YAML Array
- آیا هر آیتم Block با خط تیره و فاصله آغاز شده است؟
- آیا همه خط تیرههای یک List در یک ستون قرار دارند؟
- آیا از Tab در تورفتگی استفاده نشده است؟
- آیا Objectهای داخل List کلیدهای تکراری ندارند؟
- آیا اعضای List قرارداد نوع و ساختار قابل پیشبینی دارند؟
- آیا تفاوت List خالی، null و کلید غایب در برنامه مقصد مشخص است؟
- آیا Flow Sequenceها ویرگول درست دارند؟
- آیا فایل با Parser و Validator واقعی پروژه آزمایش شده است؟
پرسشهای متداول درباره YAML Array و List
آیا YAML Array و YAML List تفاوت دارند؟
در گفتگوهای فنی معمولاً هر دو عبارت به یک مفهوم اشاره میکنند. نام رسمی در مدل YAML، Sequence است. پس وقتی مستندات از Sequence صحبت میکنند، منظور همان ساختاری است که توسعهدهندگان اغلب List یا Array مینامند.
آیا آیتمهای YAML List باید همنوع باشند؟
از نظر Syntax اجباری نیست؛ یک Sequence میتواند Number، String، Mapping و Sequence را با هم نگه دارد. با این حال برای طراحی قابل پیشبینی، اعتبارسنجی ساده و نگهداری بهتر، همنوع یا دستکم همساختار بودن اعضا توصیه میشود.
چطور یک List خالی در YAML بنویسیم؟
از براکت خالی استفاده کنید: items: []. این مقدار با items: null و حذف کامل کلید items متفاوت است.
چرا Parser برای یک List خطای Mapping میدهد؟
زیرا Objectهای داخل List در YAML همان Mapping هستند. تورفتگی اشتباه، جاافتادن خط تیره یا کلید تکراری میتواند Parser را در مرز میان Sequence و Mapping دچار خطا کند. خط قبل از محل گزارششده را نیز بررسی کنید.
آیا میتوان List را در یک خط نوشت؟
بله. Flow Style مانند roles: [admin, editor] معتبر است. برای فهرست کوتاه مناسب است، اما برای Objectهای پیچیده یا تعداد زیاد آیتم، Block Style خواناتر خواهد بود.
ترتیب آیتمها در YAML حفظ میشود؟
بله، Sequence ذاتاً مرتب است و Parser باید ترتیب آن را حفظ کند. البته برنامه مصرفکننده میتواند بعداً داده را مرتب یا تبدیل کند.
جمعبندی
YAML Array یا Sequence راه استاندارد نمایش مجموعههای مرتب در YAML است. فرم Block با خط تیره برای بیشتر فایلهای واقعی بهترین خوانایی را دارد و فرم Flow با براکت برای Listهای کوتاه مناسب است. مهمترین نکته، حفظ تورفتگی سازگار و درک مرز میان Sequence و Mapping است. یک List میتواند Scalar، Object یا List دیگری را نگه دارد، اما معتبر بودن Syntax بهتنهایی تضمین نمیکند که طراحی داده خوب، امن یا مطابق Schema باشد. برای جلوگیری از خطا، فایل را با Parser، Validator و در صورت امکان قرارداد ساختاری پروژه بررسی کنید.