본문으로 건너뛰기 설정 파일 형식 완벽 가이드 | JSON·YAML·XML·TOML·INI 비교

설정 파일 형식 완벽 가이드 | JSON·YAML·XML·TOML·INI 비교

설정 파일 형식 완벽 가이드 | JSON·YAML·XML·TOML·INI 비교

이 글의 핵심

JSON, YAML, XML, TOML, INI, Markdown 등 프로그래밍에서 자주 사용되는 파일 형식의 특징과 차이점. 각 형식의 장단점, 사용 사례, 파싱 방법, 실전 예제로 완벽 이해.

들어가며: 설정 파일 형식의 중요성

모든 프로그래밍 프로젝트는 설정 파일을 사용합니다. package.json, docker-compose.yml, nginx.conf, README.md 등 각 형식마다 특징과 용도가 다릅니다. 올바른 형식을 선택하면 코드 가독성과 유지보수성이 크게 향상됩니다. 이 글에서 다룰 형식

  • JSON (JavaScript Object Notation)
  • YAML (YAML Ain’t Markup Language)
  • XML (eXtensible Markup Language)
  • TOML (Tom’s Obvious, Minimal Language)
  • INI (Initialization File)
  • Markdown
  • 기타 (Properties, HCL, Jsonnet)

1. JSON (JavaScript Object Notation)

JSON 파싱 내부 메커니즘

JSON 파서가 동작하는 원리:

JSON.parse(text) 내부 동작:

1. 토큰화 (Tokenization):
   
   입력 텍스트를 토큰으로 분리:
   
   {"name":"John","age":30}
   
   → 토큰 스트림:
   [ {, "name", :, "John", ,, "age", :, 30, } ]
   
   토큰 타입:
   - LEFT_BRACE: {
   - RIGHT_BRACE: }
   - LEFT_BRACKET: [
   - RIGHT_BRACKET: ]
   - STRING: "..."
   - NUMBER: 123, 3.14
   - TRUE/FALSE/NULL
   - COLON: :
   - COMMA: ,

2. 재귀 하강 파싱 (Recursive Descent Parsing):
   
   문법 규칙:
   value → object | array | string | number | true | false | null
   object → { members }
   members → pair | pair , members
   pair → string : value
   array → [ elements ]
   elements → value | value , elements
   
   파싱 과정:
   
   parseValue():
     if token == '{':
       return parseObject()
     else if token == '[':
       return parseArray()
     else if token == STRING:
       return parseString()
     else if token == NUMBER:
       return parseNumber()
   
   parseObject():
     result = {}
     expect('{')
     while token != '}':
       key = parseString()
       expect(':')
       value = parseValue()  ← 재귀!
       result[key] = value
       if token == ',': advance()
     expect('}')
     return result

3. 값 변환:
   
   "John" → JavaScript String
   30 → JavaScript Number
   true → JavaScript Boolean
   null → JavaScript null
   
   특수 처리:
   - "123" → String (따옴표 있음)
   - 123 → Number (따옴표 없음)
   - "\n" → 개행 문자 (이스케이프)
   - "\u0041" → "A" (유니코드)

4. 에러 검증:
   
   구문 오류 감지:
   - 따옴표 미매칭: {"name": "John}
   - 후행 쉼표: {"name": "John",}
   - 주석: {"name": "John"} // comment
   - 키 미인용: {name: "John"}
   
   → SyntaxError 즉시 발생

JSON 파싱 성능이 빠른 이유:

JSON 문법의 단순성:

1. LL(1) 파서로 구현 가능:
   - 한 토큰만 미리 보면 (lookahead) 결정 가능
   - 백트래킹 불필요
   - 선형 시간 O(n)

2. 타입이 명확:
   - "..."는 무조건 문자열
   - 123은 무조건 숫자
   - true/false/null은 키워드
   
   YAML은 타입 추론 필요:
   - yes → Boolean true
   - "yes" → String "yes"
   - 123 → Number
   - "123" → String
   → 복잡한 파싱 로직

3. 메모리 할당 최소화:
   - JavaScript 엔진의 네이티브 객체로 직접 변환
   - V8 엔진에서 JSON.parse는 최적화된 C++ 코드
   
   벤치마크 (1MB JSON 파일):
   - JSON.parse: ~10ms
   - YAML.parse: ~100ms (10배 느림)
   - XML: ~50ms

JSON5와 JSONC (확장):

// JSON5 (주석 허용, 후행 쉼표 허용)
{
  // 주석 가능
  name: 'John',  // 키 인용 생략 가능
  age: 30,       // 후행 쉼표 OK
}

// JSONC (JSON with Comments - VS Code 설정)
{
  "editor.fontSize": 14,  // 폰트 크기
  "editor.tabSize": 2     // 탭 크기
}

// 표준 JSON은 불가능:
{
  "name": "John",  // ❌ 주석 불가
  "age": 30,       // ❌ 후행 쉼표 불가
}

JSON이란?

JSON은 JavaScript 객체 표기법을 기반으로 한 경량 데이터 교환 형식입니다. 사람이 읽기 쉽으며, 기계가 파싱하기 쉽습니다.

JSON 기본 문법

{
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "isActive": true,
  "balance": 1234.56,
  "tags": ["developer", "designer"],
  "address": {
    "street": "123 Main St",
    "city": "Seoul",
    "zipCode": "12345"
  },
  "projects": [
    {
      "id": 1,
      "name": "Project A",
      "status": "active"
    },
    {
      "id": 2,
      "name": "Project B",
      "status": "completed"
    }
  ],
  "metadata": null
}

JSON 데이터 타입

{
  "string": "Hello, World!",
  "number": 42,
  "float": 3.14159,
  "boolean": true,
  "null": null,
  "array": [1, 2, 3, "mixed", true],
  "object": {
    "nested": "value"
  }
}

JSON 장단점

flowchart TB
    JSON[JSON]
    
    subgraph Pros[장점]
        P1[✅ 파싱 속도 빠름]
        P2[✅ JavaScript 네이티브]
        P3[✅ 간결한 문법]
        P4[✅ 널리 지원됨]
    end
    
    subgraph Cons[단점]
        C1[❌ 주석 불가]
        C2[❌ 후행 쉼표 불가]
        C3[❌ 멀티라인 문자열 불편]
        C4[❌ 날짜 타입 없음]
    end
    
    JSON --> Pros
    JSON --> Cons

JSON 사용 예시

// JavaScript
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  retries: 3
};
// JSON으로 변환
const json = JSON.stringify(config, null, 2);
console.log(json);
// JSON 파싱
const parsed = JSON.parse(json);
console.log(parsed.apiUrl);
# Python
import json
config = {
    "apiUrl": "https://api.example.com",
    "timeout": 5000,
    "retries": 3
}
# JSON으로 변환
json_str = json.dumps(config, indent=2)
print(json_str)
# JSON 파싱
parsed = json.loads(json_str)
print(parsed['apiUrl'])
# 파일 I/O
with open('config.json', 'w') as f:
    json.dump(config, f, indent=2)
with open('config.json', 'r') as f:
    loaded = json.load(f)

JSON Schema (검증)

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "age": {
      "type": "integer",
      "minimum": 0,
      "maximum": 150
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "minItems": 1
    }
  },
  "required": ["name", "email"]
}

2. YAML (YAML Ain’t Markup Language)

YAML 파싱 메커니즘과 복잡성

YAML 파서가 복잡한 이유:

YAML은 문맥 의존적 (Context-Sensitive) 문법:

1. 들여쓰기 레벨 추적:
   
   name: value
     nested: value2
       deep: value3
   
   → 파서가 현재 들여쓰기 레벨을 스택으로 관리
   → 들여쓰기 감소 시 스택 pop
   → 들여쓰기 증가 시 스택 push
   
   들여쓰기 오류:
   items:
     - name: item1
      - name: item2  ← 1칸 부족 → 에러!

2. 타입 추론 (Implicit Typing):
   
   YAML은 따옴표 없이 값의 타입 자동 추론:
   
   age: 30           → Number
   age: "30"         → String
   enabled: true     → Boolean true
   enabled: yes      → Boolean true (YAML 키워드)
   enabled: "yes"    → String "yes"
   version: 1.0      → Number 1.0
   version: "1.0"    → String "1.0"
   date: 2026-04-01  → Date 객체
   null_value: null  → null
   null_value: ~     → null (YAML 축약)
   
   → 파서가 모든 값에 대해 타입 판단 필요
   → JSON은 명시적이라 불필요

3. 복잡한 구조 표현:
   
   블록 스타일 (들여쓰기):
   items:
     - name: item1
       value: 100
     - name: item2
       value: 200
   
   플로우 스타일 (인라인):
   items: [{name: item1, value: 100}, {name: item2, value: 200}]
   
   앵커와 별칭 (재사용):
   defaults: &defaults
     timeout: 30
     retries: 3
   
   prod:
     <<: *defaults      ← defaults 내용 병합
     url: https://prod
   
   → 파서가 앵커를 추적하고 참조 시 삽입

4. 멀티라인 문자열:
   
   리터럴 (개행 유지):
   script: |
     line 1
     line 2
     line 3
   → "line 1\nline 2\nline 3"
   
   폴딩 (개행 → 공백):
   description: >
     This is a long
     description text.
   → "This is a long description text."
   
   → 특수 처리 로직 필요

5. 파싱 단계:
   
   text → Tokens → Events → Representation Graph → Native Objects
   
   Events:
   - STREAM_START
   - DOCUMENT_START
   - MAPPING_START (객체 시작)
   - SCALAR (값)
   - MAPPING_END
   - DOCUMENT_END
   - STREAM_END
   
   → JSON은 Tokens → Objects (단순)

YAML 파싱이 느린 이유:

JSON vs YAML 파싱 복잡도:

JSON:
- LL(1) 파서: 1개 토큰만 미리 봄
- 타입 명시적: "string", 123, true
- 단순 재귀 하강
- 시간 복잡도: O(n)

YAML:
- 문맥 의존: 들여쓰기 레벨 추적
- 타입 추론: yes → Boolean, "yes" → String
- 앵커/별칭 해석
- 멀티라인 처리
- 시간 복잡도: O(n) 이상 (복잡한 상수)

벤치마크 (동일한 데이터):
- JSON.parse (V8): 1x (기준)
- yaml.load (js-yaml): 10-20x
- yaml.safe_load (PyYAML): 50-100x

YAML 보안 이슈:

# ❌ 위험: yaml.load() (Python, 임의 코드 실행)
!!python/object/apply:os.system
args: ['rm -rf /']

# ✅ 안전: yaml.safe_load() (기본 타입만)
name: value
age: 30

# Node.js js-yaml:
yaml.load(text)      // ❌ 위험 (커스텀 태그 허용)
yaml.safeLoad(text)  // ✅ 안전 (기본 타입만)

YAML이란?

YAML은 사람이 읽기 쉬운 데이터 직렬화 형식입니다. 들여쓰기로 계층 구조를 표현하며, 주석을 지원합니다.

YAML 기본 문법

# 주석은 #으로 시작
# 키-값 쌍
name: John Doe
age: 30
email: john@example.com
# 불린
isActive: true
isDeleted: false
# Null
metadata: null
# 또는
metadata: ~
# 문자열 (따옴표 선택적)
city: Seoul
country: "South Korea"
description: 'Single quotes.. 설정 파일 형식 완벽 가이드에 대한 완전한 가이드입니다. 실전 예제와 함께 핵심 개념부터 고급 활용까지 다룹니다.' # 멀티라인 문자열
bio: |
  This is a multi-line string.
  It preserves line breaks.
  Very useful for long text.
summary: >
  This is a folded string.
  Line breaks are converted to spaces.
  Useful for long paragraphs.
# 배열 (리스트)
tags:
  - developer
  - designer
  - writer
# 또는 인라인
tags: ["developer", "designer", "writer"]
# 객체 (딕셔너리)
address:
  street: 123 Main St
  city: Seoul
  zipCode: "12345"
# 또는 인라인
address: {street: 123 Main St, city: Seoul, zipCode: "12345"}
# 배열 + 객체
projects:
  - id: 1
    name: Project A
    status: active
  - id: 2
    name: Project B
    status: completed
# 앵커와 별칭 (재사용)
defaults: &defaults
  timeout: 30
  retries: 3
production:
  <<: *defaults
  apiUrl: https://api.example.com
development:
  <<: *defaults
  apiUrl: http://localhost:3000

YAML 주의사항

# ❌ 탭 사용 불가 (공백만 가능)
name: value
  nested: error  # 탭으로 들여쓰기하면 에러!
# ✅ 공백 사용
name: value
  nested: correct
# ❌ 들여쓰기 불일치
items:
  - name: item1
    value: 100
   - name: item2  # 들여쓰기 오류!
# ✅ 일관된 들여쓰기
items:
  - name: item1
    value: 100
  - name: item2
    value: 200
# 특수 문자 주의
# 콜론(:)이 포함된 문자열은 따옴표 필요
url: "https://example.com"  # 따옴표 권장
time: "12:30"  # 따옴표 필수
# 숫자로 시작하는 문자열
version: "1.0"  # 따옴표 필요 (아니면 숫자로 파싱)

YAML 사용 예시

# Python
import yaml
config = {
    'name': 'MyApp',
    'version': '1.0.0',
    'database': {
        'host': 'localhost',
        'port': 5432,
        'name': 'mydb'
    },
    'features': ['auth', 'api', 'admin']
}
# YAML로 변환
yaml_str = yaml.dump(config, default_flow_style=False)
print(yaml_str)
# YAML 파싱
parsed = yaml.safe_load(yaml_str)
print(parsed['database']['host'])
# 파일 I/O
with open('config.yaml', 'w') as f:
    yaml.dump(config, f, default_flow_style=False)
with open('config.yaml', 'r') as f:
    loaded = yaml.safe_load(f)

Docker Compose 예시

version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    environment:
      - NGINX_HOST=example.com
      - NGINX_PORT=80
    depends_on:
      - app
    networks:
      - webnet
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
  
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - NODE_ENV=production
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./app:/app
      - /app/node_modules
    networks:
      - webnet
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
  
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - webnet
networks:
  webnet:
    driver: bridge
volumes:
  db-data:

3. XML (eXtensible Markup Language)

XML이란?

XML은 확장 가능한 마크업 언어로, 태그 기반으로 데이터를 구조화합니다. 엄격한 문법과 스키마 검증을 지원합니다.

XML 기본 문법

<?xml version="1.0" encoding="UTF-8"?>
<!-- 주석 -->
<configuration>
  <!-- 단순 요소 -->
  <name>MyApp</name>
  <version>1.0.0</version>
  
  <!-- 속성 -->
  <database type="postgresql" ssl="true">
    <host>localhost</host>
    <port>5432</port>
    <name>mydb</name>
    <credentials>
      <username>user</username>
      <password>pass</password>
    </credentials>
  </database>
  
  <!-- 배열 (반복 요소) -->
  <features>
    <feature name="auth" enabled="true"/>
    <feature name="api" enabled="true"/>
    <feature name="admin" enabled="false"/>
  </features>
  
  <!-- CDATA (특수 문자 포함) -->
  <description><![CDATA[
    This is a <description> with special characters: & < > " '
  ]]></description>
  
  <!-- 네임스페이스 -->
  <config xmlns="http://example.com/config"
          xmlns:db="http://example.com/database">
    <db:connection>localhost</db:connection>
  </config>
</configuration>

XML 파싱

# Python (ElementTree)
import xml.etree.ElementTree as ET
# XML 파싱
tree = ET.parse('config.xml')
root = tree.getroot()
# 요소 접근
name = root.find('name').text
print(f"Name: {name}")
# 속성 접근
db = root.find('database')
db_type = db.get('type')
print(f"Database type: {db_type}")
# 반복 요소
for feature in root.findall('.//feature'):
    name = feature.get('name')
    enabled = feature.get('enabled')
    print(f"Feature {name}: {enabled}")
# XPath 사용
host = root.find('.//database/host').text
print(f"Database host: {host}")
// JavaScript (Browser)
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
// 요소 접근
const name = xmlDoc.getElementsByTagName("name")[0].textContent;
console.log(name);
// 속성 접근
const db = xmlDoc.getElementsByTagName("database")[0];
const dbType = db.getAttribute("type");
console.log(dbType);

XML Schema (XSD)

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  
  <xs:element name="configuration">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="version" type="xs:string"/>
        <xs:element name="database" type="DatabaseType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  
  <xs:complexType name="DatabaseType">
    <xs:sequence>
      <xs:element name="host" type="xs:string"/>
      <xs:element name="port" type="xs:integer"/>
    </xs:sequence>
    <xs:attribute name="type" type="xs:string" use="required"/>
  </xs:complexType>
  
</xs:schema>

XML 사용 사례

<!-- Maven (pom.xml) -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>myapp</artifactId>
  <version>1.0.0</version>
  
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>3.2.0</version>
    </dependency>
  </dependencies>
</project>
<!-- Spring (applicationContext.xml) -->
<beans xmlns="http://www.springframework.org/schema/beans">
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="org.postgresql.Driver"/>
    <property name="url" value="jdbc:postgresql://localhost:5432/mydb"/>
  </bean>
</beans>
<!-- Android (AndroidManifest.xml) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
  <uses-permission android:name="android.permission.INTERNET"/>
  <application android:label="MyApp">
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
      </intent-filter>
    </activity>
  </application>
</manifest>

4. TOML (Tom’s Obvious, Minimal Language)

TOML이란?

TOML은 읽기 쉽고 명확한 설정 파일 형식입니다. INI의 개선 버전으로, 타입과 중첩을 지원합니다.

TOML 기본 문법

# 주석
# 키-값 쌍
name = "MyApp"
version = "1.0.0"
# 숫자
port = 8080
timeout = 30.5
# 불린
debug = true
production = false
# 날짜/시간
created_at = 2026-04-01T10:00:00Z
# 배열
tags = ["rust", "web", "api"]
# 인라인 테이블
author = { name = "John Doe", email = "john@example.com" }
# 테이블 (섹션)
[database]
host = "localhost"
port = 5432
name = "mydb"
[database.credentials]
username = "user"
password = "pass"
# 배열 테이블
[[servers]]
name = "server1"
ip = "192.168.1.1"
role = "primary"
[[servers]]
name = "server2"
ip = "192.168.1.2"
role = "backup"
# 중첩 구조
[app.cache]
enabled = true
ttl = 3600
[app.cache.redis]
host = "localhost"
port = 6379

TOML 파싱

# Python
import tomli  # Python 3.11+는 tomllib 내장
with open('config.toml', 'rb') as f:
    config = tomli.load(f)
print(config['name'])
print(config['database']['host'])
print(config['servers'][0]['name'])
# TOML 생성
import tomli_w
data = {
    'name': 'MyApp',
    'version': '1.0.0',
    'database': {
        'host': 'localhost',
        'port': 5432
    }
}
with open('output.toml', 'wb') as f:
    tomli_w.dump(data, f)
// Rust
use serde::Deserialize;
use std::fs;
#[derive(Deserialize)]
struct Config {
    name: String,
    version: String,
    database: Database,
}
#[derive(Deserialize)]
struct Database {
    host: String,
    port: u16,
}
fn main() {
    let contents = fs::read_to_string("config.toml").unwrap();
    let config: Config = toml::from_str(&contents).unwrap();
    
    println!("Name: {}", config.name);
    println!("DB Host: {}", config.database.host);
}

TOML 사용 사례

# Cargo.toml (Rust)
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1.35", features = [full] }
serde = { version = "1.0", features = [derive] }
serde_json = "1.0"
[dev-dependencies]
criterion = "0.5"
[profile.release]
opt-level = 3
lto = true
# pyproject.toml (Python)
[project]
name = "myapp"
version = "1.0.0"
description = "My Python application"
authors = [{name = "John Doe", email = "john@example.com"}]
dependencies = [
    "fastapi>=0.104.0",
    "uvicorn>=0.24.0",
]
[project.optional-dependencies]
dev = ["pytest>=7.4.0", "black>=23.0.0"]
[tool.black]
line-length = 88
target-version = ['py311']

5. INI (Initialization File)

INI란?

INI는 간단한 설정 파일 형식으로, Windows에서 널리 사용됩니다. 섹션과 키-값 쌍으로 구성됩니다.

INI 기본 문법

; 주석은 세미콜론으로 시작
# 또는 해시(#)로도 가능
; 전역 설정 (섹션 없음)
app_name = MyApp
version = 1.0.0
; 섹션
[database]
host = localhost
port = 5432
name = mydb
username = user
password = pass
[cache]
enabled = true
ttl = 3600
type = redis
[cache.redis]
host = localhost
port = 6379
; 배열 (비표준, 구현마다 다름)
[features]
feature1 = auth
feature2 = api
feature3 = admin
; 또는
features = auth,api,admin

INI 파싱

# Python
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# 값 읽기
app_name = config['DEFAULT']['app_name']
db_host = config['database']['host']
db_port = config.getint('database', 'port')
cache_enabled = config.getboolean('cache', 'enabled')
print(f"App: {app_name}")
print(f"DB: {db_host}:{db_port}")
print(f"Cache: {cache_enabled}")
# 값 쓰기
config['database']['host'] = 'db.example.com'
with open('config.ini', 'w') as f:
    config.write(f)

INI 사용 사례

; php.ini
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
serialize_precision = -1
disable_functions = exec,passthru,shell_exec,system
[Date]
date.timezone = Asia/Seoul
[Session]
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
session.gc_maxlifetime = 1440
; .gitconfig
[user]
    name = John Doe
    email = john@example.com
[core]
    editor = vim
    autocrlf = input
[alias]
    st = status
    co = checkout
    br = branch
    ci = commit

6. Markdown

Markdown이란?

Markdown은 일반 텍스트로 서식 있는 문서를 작성하는 경량 마크업 언어입니다.

Markdown 기본 문법

# 제목 1 (H1)
## 제목 2 (H2)
### 제목 3 (H3)
**굵게** 또는 __굵게__
*기울임* 또는 _기울임_
~~취소선~~
`인라인 코드`
> 인용문
> 여러 줄 가능
- 순서 없는 리스트
- 항목 2
  - 중첩 항목
  - 중첩 항목 2
1. 순서 있는 리스트
2. 항목 2
3. 항목 3
[링크 텍스트](https://example.com)
![이미지 대체 텍스트](image.png)
---
수평선
| 컬럼 1 | 컬럼 2 | 컬럼 3 |
|--------|--------|--------|
| 값 1   | 값 2   | 값 3   |
| 값 4   | 값 5   | 값 6   |
```코드 블록```
여러 줄 코드
```python
# 언어 지정 (신택스 하이라이팅)
def hello():
    print("Hello, World!")
  • 체크박스 (미완료)
  • 체크박스 (완료)
### GitHub Flavored Markdown (GFM)
```markdown
# GitHub 확장 기능
## 작업 목록

- [x] 완료된 작업
- [ ] 미완료 작업
- [ ] 진행 중
## 테이블 정렬

| Left | Center | Right |
|:-----|:------:|------:|
| 왼쪽 | 중앙   | 오른쪽 |
## 이모지

:smile: :rocket: :tada:
## 멘션

@username
## 이슈 참조
#123
## 코드 블록 파일명

```javascript:app.js
console.log("Hello");

접기/펼치기

클릭하여 펼치기 숨겨진 내용
## 수식 (LaTeX)

$E = mc^2$ $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$

### Markdown 파싱
```python
# Python (markdown 라이브러리)
import markdown
md_text = """
# Hello
This is **bold** and *italic*.
- Item 1
- Item 2
"""
html = markdown.markdown(md_text)
print(html)
# <h1>Hello</h1>
# <p>This is <strong>bold</strong> and <em>italic</em>.</p>
# <ul>
# <li>Item 1</li>
# <li>Item 2</li>
# </ul>
# 확장 기능 사용
html = markdown.markdown(md_text, extensions=['tables', 'fenced_code', 'toc'])
// JavaScript (marked 라이브러리)
import { marked } from 'marked';
const mdText = `
# Hello
This is **bold** text.
`;
const html = marked.parse(mdText);
console.log(html);

7. 형식 비교 및 선택 가이드

동일한 데이터 표현

JSON

{
  "app": {
    "name": "MyApp",
    "version": "1.0.0",
    "features": ["auth", "api"]
  },
  "database": {
    "host": "localhost",
    "port": 5432
  }
}

YAML

# 실행 예제
app:
  name: MyApp
  version: 1.0.0
  features:
    - auth
    - api
database:
  host: localhost
  port: 5432

XML

// 실행 예제
<?xml version="1.0"?>
<config>
  <app>
    <name>MyApp</name>
    <version>1.0.0</version>
    <features>
      <feature>auth</feature>
      <feature>api</feature>
    </features>
  </app>
  <database>
    <host>localhost</host>
    <port>5432</port>
  </database>
</config>

TOML

# 실행 예제
[app]
name = "MyApp"
version = "1.0.0"
features = ["auth", "api"]
[database]
host = "localhost"
port = 5432

INI

// 실행 예제
[app]
name = MyApp
version = 1.0.0
features = auth,api
[database]
host = localhost
port = 5432

비교표

특성JSONYAMLXMLTOMLINIMarkdown
가독성⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
파싱 속도⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
주석
타입 안정성⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐N/A
중첩 구조제한적
파일 크기작음중간중간작음중간
스키마 검증

사용 사례별 추천

flowchart TD
    Start[파일 형식 선택] --> Q1{용도는?}
    
    Q1 -->|API 응답| JSON["✅ JSON\n빠른 파싱"]
    Q1 -->|설정 파일| Q2{복잡도는?}
    Q1 -->|문서| Markdown["✅ Markdown\nREADME, 블로그"]
    Q1 -->|빌드 설정| Q3{언어는?}
    
    Q2 -->|간단| INI["✅ INI\n간단한 설정"]
    Q2 -->|중간| TOML["✅ TOML\nRust, Python"]
    Q2 -->|복잡| YAML["✅ YAML\nDocker, K8s"]
    
    Q3 -->|Java| XML["✅ XML\nMaven, Spring"]
    Q3 -->|JavaScript| JSON["✅ JSON\npackage.json"]
    Q3 -->|Rust| TOML["✅ TOML\nCargo.toml"]
    Q3 -->|Python| TOML2["✅ TOML\npyproject.toml"]

프로젝트별 사용 현황

프로젝트형식파일명
Node.jsJSONpackage.json
PythonTOMLpyproject.toml
RustTOMLCargo.toml
GoGogo.mod
DockerYAMLdocker-compose.yml
KubernetesYAMLdeployment.yaml
AnsibleYAMLplaybook.yml
MavenXMLpom.xml
GradleGroovybuild.gradle
NginxCustomnginx.conf
ApacheCustomhttpd.conf

8. 실전 변환 및 검증

형식 간 변환

#!/usr/bin/env python3
"""
설정 파일 형식 변환 도구
"""
import json
import yaml
import tomli
import tomli_w
import xml.etree.ElementTree as ET
from pathlib import Path
class ConfigConverter:
    @staticmethod
    def json_to_yaml(json_file, yaml_file):
        """JSON → YAML"""
        with open(json_file, 'r') as f:
            data = json.load(f)
        
        with open(yaml_file, 'w') as f:
            yaml.dump(data, f, default_flow_style=False, allow_unicode=True)
        
        print(f"✅ Converted: {json_file}{yaml_file}")
    
    @staticmethod
    def yaml_to_json(yaml_file, json_file):
        """YAML → JSON"""
        with open(yaml_file, 'r') as f:
            data = yaml.safe_load(f)
        
        with open(json_file, 'w') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        
        print(f"✅ Converted: {yaml_file}{json_file}")
    
    @staticmethod
    def json_to_toml(json_file, toml_file):
        """JSON → TOML"""
        with open(json_file, 'r') as f:
            data = json.load(f)
        
        with open(toml_file, 'wb') as f:
            tomli_w.dump(data, f)
        
        print(f"✅ Converted: {json_file}{toml_file}")
    
    @staticmethod
    def toml_to_json(toml_file, json_file):
        """TOML → JSON"""
        with open(toml_file, 'rb') as f:
            data = tomli.load(f)
        
        with open(json_file, 'w') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        
        print(f"✅ Converted: {toml_file}{json_file}")
# 사용
converter = ConfigConverter()
converter.json_to_yaml('config.json', 'config.yaml')
converter.yaml_to_json('config.yaml', 'config.json')
converter.json_to_toml('config.json', 'config.toml')

검증 도구

# JSON 검증
jq . config.json
# 또는
python -m json.tool config.json
# YAML 검증
yamllint config.yaml
# YAML → JSON (yq)
yq eval -o=json config.yaml
# XML 검증
xmllint --noout config.xml
# TOML 검증 (Python)
python -c "import tomli; tomli.load(open('config.toml', 'rb'))"

온라인 도구

# jq (JSON 쿼리)
cat config.json | jq '.database.host'
# "localhost"
# 배열 필터링
cat config.json | jq '.servers[] | select(.role == "primary")'
# 변환
cat config.json | jq '.database'
# yq (YAML 쿼리)
cat config.yaml | yq '.database.host'
# xmllint (XML 쿼리)
xmllint --xpath '//database/host/text()' config.xml

기타 형식

Properties (Java)

# application.properties (Spring Boot)
server.port=8080
server.address=0.0.0.0
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=pass
# 배열
spring.profiles.active=dev,debug
# 멀티라인 (백슬래시)
app.description=This is a very long \
                description that spans \
                multiple lines.

HCL (HashiCorp Configuration Language)

# Terraform
variable "region" {
  description = "AWS region"
  type        = string
  default     = "us-west-2"
}
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  
  tags = {
    Name = "WebServer"
    Environment = "production"
  }
}
output "instance_ip" {
  value = aws_instance.web.public_ip
}

Jsonnet (JSON 템플릿)

// config.jsonnet
local env = std.extVar('env');
local base = {
  name: 'MyApp',
  version: '1.0.0',
};
local envConfig = {
  dev: {
    apiUrl: 'http://localhost:3000',
    debug: true,
  },
  prod: {
    apiUrl: 'https://api.example.com',
    debug: false,
  },
};
base + envConfig[env]
# 실행
jsonnet -V env=dev config.jsonnet
# {
#   "name": "MyApp",
#   "version": "1.0.0",
#   "apiUrl": "http://localhost:3000",
#   "debug": true
# }

ENV 파일

# .env
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
REDIS_URL=redis://localhost:6379
API_KEY=secret-key-123
DEBUG=false
# 배열 (비표준)
ALLOWED_HOSTS=localhost,example.com,*.example.com
# Python (python-dotenv)
from dotenv import load_dotenv
import os
load_dotenv()
port = int(os.getenv('PORT', 3000))
database_url = os.getenv('DATABASE_URL')
debug = os.getenv('DEBUG', 'false').lower() == 'true'
print(f"Port: {port}")
print(f"Database: {database_url}")
print(f"Debug: {debug}")

실전 팁

1. 주석 처리

// JSON은 주석 불가 → JSON5 사용
// package.json5
{
  // 프로젝트 정보
  name: "myapp",
  version: "1.0.0",
  
  // 의존성
  dependencies: {
    express: "^4.18.0",  // 후행 쉼표 가능
  },
}
// 또는 _comment 키 사용 (비표준)
{
  "_comment": "이것은 주석입니다",
  "name": "myapp"
}

2. 환경별 설정

# config.yaml
default: &default
  timeout: 30
  retries: 3
development:
  <<: *default
  apiUrl: http://localhost:3000
  debug: true
production:
  <<: *default
  apiUrl: https://api.example.com
  debug: false
# Python으로 환경별 로드
import yaml
import os
env = os.getenv('ENV', 'development')
with open('config.yaml') as f:
    config = yaml.safe_load(f)
app_config = config[env]
print(app_config)

3. 민감한 정보 관리

# config.yaml (민감한 정보 제외)
database:
  host: localhost
  port: 5432
  name: mydb
  # username과 password는 환경 변수로
# .env (버전 관리 제외)
DB_USERNAME=user
DB_PASSWORD=secret
# .gitignore
.env
*.secret.yaml
# Python으로 병합
import yaml
import os
with open('config.yaml') as f:
    config = yaml.safe_load(f)
# 환경 변수로 덮어쓰기
config['database']['username'] = os.getenv('DB_USERNAME')
config['database']['password'] = os.getenv('DB_PASSWORD')

4. 스키마 검증

# JSON Schema 검증
import json
import jsonschema
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": [name]
}
data = {"name": "John", "age": 30}
try:
    jsonschema.validate(data, schema)
    print("✅ Valid")
except jsonschema.ValidationError as e:
    print(f"❌ Invalid: {e.message}")

실전 설정 파일 예시

Node.js 프로젝트

// package.json
{
  "name": "myapp",
  "version": "1.0.0",
  "description": "My awesome application",
  "main": "dist/index.js",
  "scripts": {
    "start": "node dist/index.js",
    "dev": "nodemon src/index.ts",
    "build": "tsc",
    "test": "jest",
    "lint": "eslint src/**/*.ts"
  },
  "dependencies": {
    "express": "^4.18.0",
    "dotenv": "^16.0.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "nodemon": "^3.0.0",
    "jest": "^29.0.0"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": [ES2022],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": [src/**/*],
  "exclude": ["node_modules", "dist"]
}

Python 프로젝트

# pyproject.toml
[project]
name = "myapp"
version = "1.0.0"
description = "My Python application"
readme = "README.md"
requires-python = ">=3.11"
license = {text = "MIT"}
authors = [
    {name = "John Doe", email = "john@example.com"}
]
dependencies = [
    "fastapi>=0.104.0",
    "uvicorn[standard]>=0.24.0",
    "sqlalchemy>=2.0.0",
    "pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = [
    "pytest>=7.4.0",
    "black>=23.0.0",
    "mypy>=1.7.0",
    "ruff>=0.1.0",
]
[project.scripts]
myapp = "myapp.cli:main"
[tool.black]
line-length = 88
target-version = ['py311']
include = '\.pyi?$'
[tool.pytest.ini_options]
testpaths = [tests]
python_files = [test_*.py]
python_functions = [test_*]
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
[build-system]
requires = ["setuptools>=68.0.0", "wheel"]
build-backend = "setuptools.build_meta"

Rust 프로젝트

# Cargo.toml
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
authors = ["John Doe <john@example.com>"]
description = "My Rust application"
license = "MIT"
repository = "https://github.com/user/myapp"
[dependencies]
tokio = { version = "1.35", features = [full] }
axum = "0.7"
serde = { version = "1.0", features = [derive] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls"] }
[dev-dependencies]
criterion = "0.5"
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = true
[[bin]]
name = "myapp"
path = "src/main.rs"
[[bench]]
name = "my_benchmark"
harness = false

Kubernetes 설정

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
    version: v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:
      containers:
      - name: myapp
        image: myapp:1.0.0
        ports:
        - containerPort: 8080
          protocol: TCP
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: url
        - name: REDIS_URL
          value: redis://redis:6379
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
      imagePullSecrets:
      - name: registry-secret
---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: LoadBalancer

파싱 성능 비교

벤치마크

import json
import yaml
import tomli
import time
data = {
    'app': {
        'name': 'MyApp',
        'version': '1.0.0',
        'features': ['auth', 'api', 'admin'] * 100
    },
    'database': {
        'host': 'localhost',
        'port': 5432
    }
}
# JSON 직렬화/역직렬화
start = time.time()
for _ in range(1000):
    json_str = json.dumps(data)
    parsed = json.loads(json_str)
json_time = time.time() - start
# YAML 직렬화/역직렬화
start = time.time()
for _ in range(1000):
    yaml_str = yaml.dump(data)
    parsed = yaml.safe_load(yaml_str)
yaml_time = time.time() - start
print(f"JSON: {json_time:.3f}s")
print(f"YAML: {yaml_time:.3f}s")
print(f"YAML은 JSON보다 {yaml_time/json_time:.1f}배 느림")
# 일반적인 결과:
# JSON: 0.123s
# YAML: 1.456s
# YAML은 JSON보다 11.8배 느림

정리

형식 선택 플로우차트

flowchart TD
    Start[설정 파일 형식 선택] --> Q1{주석 필요?}
    
    Q1 -->|No| Q2{파싱 속도 중요?}
    Q1 -->|Yes| Q3{복잡도는?}
    
    Q2 -->|Yes| JSON["✅ JSON\n- API 응답\n- 빠른 파싱"]
    Q2 -->|No| Q3
    
    Q3 -->|간단| INI["✅ INI\n- 간단한 설정\n- 레거시 호환"]
    Q3 -->|중간| TOML["✅ TOML\n- Python/Rust\n- 명확한 문법"]
    Q3 -->|복잡| YAML["✅ YAML\n- Docker/K8s\n- 가독성 최고"]
    
    Start --> Q4{문서 작성?}
    Q4 -->|Yes| MD["✅ Markdown\n- README\n- 블로그"]
    
    Start --> Q5{Java 프로젝트?}
    Q5 -->|Yes| XML["✅ XML\n- Maven\n- Spring"]

핵심 원칙

# 1. API 응답 → JSON
@app.get("/api/users")
def get_users():
    return {"users": [...]}  # JSON
# 2. 설정 파일 → YAML 또는 TOML
# config.yaml
database:
  host: localhost
  port: 5432
# 3. 문서 → Markdown
# README.md
# My Project
This is a description.
# 4. 빌드 설정 → 언어별
# package.json (Node.js)
# Cargo.toml (Rust)
# pom.xml (Java)
# 5. 간단한 설정 → INI
# app.ini
[database]
host = localhost

장단점 요약

형식최고 장점최대 단점추천 용도
JSON빠른 파싱주석 없음API, 데이터 교환
YAML가독성느린 파싱Docker, K8s, CI/CD
XML스키마 검증장황함Java, SOAP, RSS
TOML명확한 문법제한적 지원Rust, Python 설정
INI단순함표준 없음간단한 설정
Markdown읽기 쉬움데이터 구조 표현 제한문서, README

베스트 프랙티스

# ✅ 권장 사항
# 1. 일관된 들여쓰기 (YAML)
app:
  name: MyApp  # 2칸
  version: 1.0.0
# 2. 주석 활용 (YAML, TOML)
# 데이터베이스 설정
[database]
host = "localhost"  # 개발 환경에서는 localhost
# 3. 환경 변수 분리
# config.yaml (버전 관리)
database:
  host: ${DB_HOST}
  port: ${DB_PORT}
# .env (버전 관리 제외)
DB_HOST=localhost
DB_PORT=5432
# 4. 스키마 검증
# JSON Schema, YAML Schema 사용
# 5. 민감한 정보 암호화
# SOPS, Vault 등 사용

변환 치트시트

명령줄 도구

# JSON → YAML
cat config.json | yq -P > config.yaml
# YAML → JSON
cat config.yaml | yq -o=json > config.json
# JSON 포맷팅
cat config.json | jq . > formatted.json
# YAML 검증
yamllint config.yaml
# XML 포맷팅
xmllint --format config.xml
# JSON 병합
jq -s '.[0] * .[1]' base.json override.json > merged.json
# YAML 병합
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' base.yaml override.yaml

프로그래밍 언어별

# Python: 모든 형식 지원
import json        # 내장
import yaml        # pip install pyyaml
import tomli       # pip install tomli
import configparser  # 내장 (INI)
import xml.etree.ElementTree as ET  # 내장
# JavaScript/Node.js
const json = require('./config.json');  // 네이티브
const yaml = require('js-yaml');
const toml = require('toml');
const ini = require('ini');
# Go
import (
    "encoding/json"
    "gopkg.in/yaml.v3"
    "github.com/BurntSushi/toml"
    "gopkg.in/ini.v1"
)
# Rust
use serde_json;  // JSON
use serde_yaml;  // YAML
use toml;        // TOML

실전 시나리오

시나리오 1: 마이크로서비스 설정

# config/base.yaml
app:
  name: MyService
  version: 1.0.0
  
logging:
  level: info
  format: json
# config/dev.yaml
app:
  debug: true
database:
  host: localhost
  port: 5432
# config/prod.yaml
app:
  debug: false
database:
  host: db.example.com
  port: 5432
  ssl: true
  pool_size: 20
# Python으로 병합
import yaml
from pathlib import Path
def load_config(env='dev'):
    """환경별 설정 로드"""
    base = yaml.safe_load(Path('config/base.yaml').read_text())
    env_config = yaml.safe_load(Path(f'config/{env}.yaml').read_text())
    
    # 딥 머지
    def deep_merge(base, override):
        for key, value in override.items():
            if key in base and isinstance(base[key], dict) and isinstance(value, dict):
                deep_merge(base[key], value)
            else:
                base[key] = value
        return base
    
    return deep_merge(base, env_config)
config = load_config('prod')
print(config)

시나리오 2: CI/CD 파이프라인

# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
env:
  NODE_VERSION: '18'
  REGISTRY: ghcr.io
jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        files: ./coverage/lcov.info
  
  build:
    needs: test
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Build Docker image
      run: |
        docker build -t ${{ env.REGISTRY }}/myapp:${{ github.sha }} .
    
    - name: Push to registry
      if: github.ref == 'refs/heads/main'
      run: |
        echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
        docker push ${{ env.REGISTRY }}/myapp:${{ github.sha }}
  
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Deploy to production
      run: |
        kubectl set image deployment/myapp myapp=${{ env.REGISTRY }}/myapp:${{ github.sha }}

에디터 설정

VS Code

// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "editor.tabSize": 2,
  "files.associations": {
    "*.yaml": "yaml",
    "*.yml": "yaml",
    "Dockerfile*": "dockerfile"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 2
  },
  "[yaml]": {
    "editor.defaultFormatter": "redhat.vscode-yaml",
    "editor.insertSpaces": true,
    "editor.tabSize": 2,
    "editor.autoIndent": "advanced"
  },
  "[markdown]": {
    "editor.wordWrap": "on",
    "editor.quickSuggestions": false
  },
  "yaml.schemas": {
    "https://json.schemastore.org/github-workflow.json": ".github/workflows/*.yml"
  }
}

EditorConfig

# .editorconfig
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{js,jsx,ts,tsx,json}]
indent_style = space
indent_size = 2
[*.{yaml,yml}]
indent_style = space
indent_size = 2
[*.py]
indent_style = space
indent_size = 4
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

정리

형식별 추천 사용처

flowchart TB
    subgraph API[API & 데이터 교환]
        JSON_API["JSON\nREST API 응답"]
        XML_API["XML\nSOAP, RSS"]
    end
    
    subgraph Config[설정 파일]
        YAML_Config["YAML\nDocker, K8s, Ansible"]
        TOML_Config["TOML\nRust, Python"]
        INI_Config["INI\n간단한 설정"]
    end
    
    subgraph Build[빌드 설정]
        JSON_Build["JSON\npackage.json, tsconfig.json"]
        XML_Build["XML\npom.xml, build.gradle"]
        TOML_Build["TOML\nCargo.toml, pyproject.toml"]
    end
    
    subgraph Doc[문서]
        MD["Markdown\nREADME, 블로그, Wiki"]
    end

선택 가이드 요약

✅ JSON 사용:
- REST API 응답
- 웹 애플리케이션 데이터
- JavaScript 프로젝트
- 파싱 속도가 중요한 경우
✅ YAML 사용:
- Docker Compose
- Kubernetes 매니페스트
- CI/CD 파이프라인 (GitHub Actions, GitLab CI)
- Ansible Playbook
- 복잡한 설정 파일
✅ XML 사용:
- Maven (pom.xml)
- Spring 설정
- Android 매니페스트
- SOAP 웹 서비스
- RSS/Atom 피드
✅ TOML 사용:
- Rust 프로젝트 (Cargo.toml)
- Python 프로젝트 (pyproject.toml)
- 명확한 설정 파일
✅ INI 사용:
- 간단한 애플리케이션 설정
- 레거시 시스템
- PHP 설정 (php.ini)
✅ Markdown 사용:
- README 파일
- 문서화
- 블로그 포스트
- GitHub Wiki

체크리스트

JSON

  • 주석 필요 없음 확인
  • 파싱 속도가 중요함
  • JavaScript와 호환 필요
  • 스키마 검증 고려

YAML

  • 들여쓰기 일관성 유지 (공백만)
  • 탭 사용 금지
  • 따옴표 규칙 이해
  • yamllint로 검증

XML

  • 스키마 정의 (XSD)
  • 네임스페이스 사용 고려
  • CDATA 섹션 활용
  • xmllint로 검증

TOML

  • 섹션 구조 설계
  • 날짜/시간 형식 활용
  • 배열 테이블 이해

Markdown

  • 일관된 스타일 가이드
  • 링크 검증
  • 코드 블록 언어 지정
  • 목차 자동 생성 고려


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. JSON, YAML, XML, TOML, INI, Markdown 등 프로그래밍에서 자주 사용되는 파일 형식의 특징과 차이점. 각 형식의 장단점, 사용 사례, 파싱 방법, 실전 예제로 완벽 이해. Start now. 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.

참고 자료


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

JSON, YAML, XML, TOML, INI, Markdown, 설정파일, config 등으로 검색하시면 이 글이 도움이 됩니다.