JSON Toolkit

Batas Konversi JSON ↔ YAML dan XML

Intinya: Klaim bahwa JSON adalah subset YAML hanya menjamin satu arah, dan XML tidak memiliki pemetaan JSON resmi sama sekali — semuanya bersandar pada konvensi.

Menengah±12 menit bacaDiterbitkan 2026-10-30Diperbarui 2026-10-30
Sampul untuk batas konversi JSON ↔ YAML dan XML

Intinya: gunakan JSON sebagai format perantara: parse sumbernya menjadi model data, lalu serialisasi ke target; sebelum mengonversi, tentukan apakah komentar, atribut XML dan namespace, serta tipe numerik atau boolean harus bertahan.

Apakah pipeline konversi dapat digunakan tidak bergantung pada seberapa cantik outputnya, melainkan pada apakah Anda menyadari berapa banyak yang telah dibuangnya.

1. JSON dan YAML: penampungan satu arah

Spesifikasi YAML 1.2 menyatakannya dengan jelas: JSON adalah subset dari YAML. Artinya, JSON valid apa pun adalah YAML valid:

{"name": "json", "tags": ["a", "b"], "count": 3}

Cuplikan ini adalah JSON sekaligus YAML flow style. Sebaliknya tidak berlaku.

Fitur JSON YAML 1.2
Komentar ✗ ✓
Anchor dan alias ✗ ✓
Beberapa dokumen (---) ✗ ✓
Kunci non-string ✗ ✓ (1: a, true: b)
Kunci kompleks ✗ ✓ (? [a, b])
Sensitif indentasi ✗ ✓ (indentasi tab ditolak)
Inferensi tipe eksplisit implisit (0o17, 0x1F, .inf)
Keterbacaan satu baris baik buruk (konten panjang bergantung pada sintaks folding)

1.1 Inferensi tipe adalah jebakan terbesar

YAML mem-parsing sebagian nilai yang tampak seperti string menjadi tipe lain:

zip: 01234        # string or octal integer? the YAML 1.2 core schema treats it as a string
version: 1.10     # 1.1 (a float); the semantics are lost
country: NO       # a string in YAML 1.2; boolean false in YAML 1.1
date: 2026-10-30  # some implementations parse it as a date object

Contoh NO telah membakar banyak orang: dengan parser YAML 1.1 (sebagian pustaka lama), country: NO menjadi false. Penangkalnya: kutip setiap pengenal yang "tampak seperti angka atau boolean", seperti version: "1.10".

1.2 Anchor, alias, dan beberapa dokumen

defaults: &defaults
  retries: 3
  timeout: 30

serviceA:
  <<: *defaults
  host: a.example.com

---
serviceB:
  <<: *defaults
  host: b.example.com

Setelah memperluas anchor dan mengonversi ke JSON, Anda biasanya berakhir dengan dua object konfigurasi terduplikasi, atau dengan satu array (beberapa dokumen harus menjadi [{...}, {...}]). Either way, anchor tidak dipulihkan pada konversi balik — kehilangan itu tidak dapat dihindari.

1.3 Konversi yang mempertahankan komentar

Sebagian besar pustaka membuang komentar begitu saja selama konversi. Saat Anda perlu mempertahankannya, gunakan Document API dari paket yaml:

import { parseDocument } from 'yaml';

const document = parseDocument(`
# Service configuration
port: 8080
`);

document.set('port', 3000);
console.log(document.toString());
// # Service configuration
// port: 3000

Ujiannya sederhana: jika file ini akan diedit manusia berulang kali, jangan mengambil jalur "parse → object → serialize".

1.4 Cara memverifikasi konsistensi round-trip

/**
 * Verifies round-trip consistency for JSON → YAML → JSON.
 * @param sourceValue Original JSON value
 * @param stringify YAML serialization function
 * @param parse YAML parsing function
 * @returns Whether the two results are exactly equal
 */
function isRoundTripStable(
  sourceValue: unknown,
  stringify: (input: unknown) => string,
  parse: (input: string) => unknown,
): boolean {
  const yamlText = stringify(sourceValue);
  const restored = parse(yamlText);
  return JSON.stringify(restored) === JSON.stringify(sourceValue);
}

Menjalankannya terhadap data nyata lebih bernilai daripada membaca dokumentasi sepuluh kali. Pastikan set sampel Anda mencakup: null, string kosong, array kosong, "00", "1e5", nol negatif, integer yang lebih besar dari 2^53, dan string panjang berisi baris baru.

2. JSON dan XML: tidak ada pemetaan standar

XML mendahului JSON jauh lebih lama dan memiliki kemampuan struktural yang jauh lebih kuat (atribut, namespace, mixed content, DTD). Di antara keduanya tidak ada spesifikasi pemetaan resmi; setiap alat melakukan hal yang sama: memilih konvensi, lalu berusaha tidak kehilangan banyak.

2.1 Konvensi umum

Konvensi Representasi Contoh
Elemen → kunci object Elemen bernama sama menjadi field <a>1</a> → {"a": "1"}
Atribut → prefiks @ @name <a id="1"/> → {"a": {"@id": "1"}}
Teks → #text Ketika ada atribut sekaligus teks <a id="1">hi</a> → {"a": {"@id": "1", "#text": "hi"}}
Elemen berulang → array Dua kemunculan atau lebih menjadi array <i>1</i><i>2</i> → {"i": ["1","2"]}
Namespace → prefiks ns:tag <ns:tag/> → {"ns:tag": ...}
<order id="A1001">
  <item sku="X1" qty="2">笔记本</item>
  <item sku="X2" qty="1">钢笔</item>
</order>
{
  "order": {
    "@id": "A1001",
    "item": [
      { "@sku": "X1", "@qty": "2", "#text": "笔记本" },
      { "@sku": "X2", "@qty": "1", "#text": "钢笔" }
    ]
  }
}

2.2 Lima kehilangan yang tidak dapat dihindari

  1. Urutan elemen: object JSON tidak berurutan, sementara XML adalah urutan elemen yang berurutan;
  2. Atribut vs elemen anak: keduanya membawa semantik berbeda di XML, tetapi keduanya menjadi field biasa di JSON;
  3. Mixed content: struktur seperti <p>你好 <b>世界</b> 再见</p> tidak dapat diekspresikan dengan object biasa;
  4. Deklarasi namespace: xmlns adalah konsep scoping; setelah diratakan menjadi field, scopenya hilang;
  5. CDATA dan entity: <![CDATA[...]]> dan &amp; tidak lebih dari teks di JSON.

2.3 Dilema "satu elemen atau array"

<list><item>1</item></list>

Dengan satu item, xml2js mengembalikan object secara default dan hanya mengembalikan array setelah ada dua. Akibatnya, kode front-end harus menulis Array.isArray(x) ? x : [x].

Penangkalnya: aktifkan opsi "always array" saat parsing, atau deklarasikan field sebagai tipe array berdasarkan schema.

import { parseStringPromise } from 'xml2js';

const parsed = await parseStringPromise(xmlText, {
  explicitArray: true,   // return an array even for a single element
  trim: true,
  explicitRoot: false,
});

2.4 Pengingat keamanan

Sebelum mem-parsing XML tak tepercaya Anda harus menonaktifkan external entity, jika tidak Anda dapat memicu XXE (membaca file lokal, memindai jaringan internal):

// In the Node ecosystem, DTDs and external entities are usually disabled through parser options
const parserOptions = { doctype: false, externalEntities: false };

XML → JSON hanyalah lapisan pertama konversi; mengonversi tidak menghilangkan permukaan serangan yang dibawa XML.

3. Di mana masing-masing dari tiga format cocok

Skenario Format yang disarankan Alasan
API HTTP publik JSON Didukung secara native oleh browser dan setiap bahasa
Konfigurasi yang dipelihara tangan YAML Komentar, indentasi, keterbacaan
Dokumen yang membutuhkan schema kuat dan namespace (SOAP, Office Open XML, SVG) XML Kemampuan struktural dan ekosistem yang sudah ada
Interaksi dengan perkakas operasional (K8s, CI) YAML Default ekosistem
Persistensi, cache, log JSON / JSONL Universal dan tanpa dependensi

4. Catatan implementasi

import { stringify as toYaml } from 'yaml';

/**
 * Converts a JSON value to YAML text while keeping Chinese characters unescaped.
 * @param value The JSON value to convert
 * @returns The YAML text
 */
function jsonToYaml(value: unknown): string {
  return toYaml(value, {
    indent: 2,
    lineWidth: 0,      // disable automatic wrapping so long strings are not split
    defaultStringType: 'QUOTE_DOUBLE',
  });
}

Beberapa opsi praktis:

  • lineWidth: 0 mematikan pembungkusan otomatis; jika tidak, URL panjang terpecah ke beberapa baris dan menjadi sulit dibaca;
  • mengutip semuanya dengan kutip ganda mencegah nilai seperti NO dan 1.10 disalahbaca;
  • untuk data dengan presisi numerik sensitif, konversi ke string sebelum serialisasi.

Untuk arah XML, tetapkan satu fungsi pemetaan tunggal dan letakkan "prefiks atribut", "nama kunci teks", dan "strategi array" ke dalam signature-nya alih-alih menyebarkannya:

type XmlMappingOptions = {
  attributePrefix: string;
  textKey: string;
  alwaysArray: boolean;
};

const defaultMapping: XmlMappingOptions = {
  attributePrefix: '@',
  textKey: '#text',
  alwaysArray: false,
};

5. Daftar periksa

  • [ ] Setiap pengenal "mirip angka/boolean" di YAML dikutip;
  • [ ] Set sampel validasi untuk JSON → YAML → JSON didefinisikan dan dicakup tes;
  • [ ] Saat komentar harus dipertahankan, Document API digunakan alih-alih round trip object;
  • [ ] Konvensi pemetaan XML dituliskan dan tim berbagi satu set parameter;
  • [ ] DTD dan external entity dinonaktifkan saat mem-parsing XML tak tepercaya;
  • [ ] Jumlah byte dan jumlah field dibandingkan sebelum dan sesudah konversi, dan anomali apa pun memicu peringatan.

FAQ

Bagaimana cara memilih arah konversi antara JSON, YAML, dan XML?

Utamakan JSON sebagai format perantara: parse YAML dan XML menjadi model data lebih dulu, lalu serialisasi dari model itu alih-alih menulis ulang teks. Gunakan YAML Document API saat komentar harus bertahan, dan tetapkan satu konvensi pemetaan XML sebelum Anda membutuhkan atribut atau namespace.

Mengapa konversi XML ke JSON kehilangan atribut dan namespace?

JSON tidak memiliki konsep atribut atau namespace, sehingga atribut XML, prefiks, dan URI namespace harus dilipat menjadi kunci biasa, umumnya dengan prefiks @ atau node #text. Begitu aturan pemetaan menyimpang, XML yang sama menghasilkan JSON berbeda dan tidak dapat melakukan round-trip.

Haruskah saya mempertahankan JSON, YAML, dan XML dalam sinkronisasi dua arah jangka panjang?

Tidak. Komentar, anchor, atribut XML, dan namespace bersifat lossy lintas format, dan sinkronisasi dua arah terus mengakumulasi perbedaan. Pilih satu format sumber dan perlakukan yang lain sebagai ekspor sekali jalan atau tampilan sementara.

Referensi

Artikel terkait

Mengonversi JSON ke dan dari CSV serta Data Tabular

CSV bersifat dua dimensi, JSON berbentuk pohon. Bagian tersulit dari konversi bukanlah kode — melainkan memutuskan di awal bagaimana array diratakan dan bagaimana tipe dipertahankan.

Pemula±10 menit bacaDiperbarui 2026-10-30

Mengelola JSON untuk Konfigurasi, Fixture, dan Data Lokal

Konfigurasi harus berlapis dan divalidasi; fixture harus deterministik, terbaca, dan bisa di-diff. Jika dua jenis file ini dikelola dengan buruk, biaya troubleshooting tetap tinggi untuk waktu lama.

Pemula±10 menit bacaDiperbarui 2026-10-30

JSON ke YAML lewat baris perintah: empat jebakan di balik satu perintah yq

Perintah yang paling sering disalin dari tutorial, yq -P input.json > output.yaml, pada yq v4 tetap mengeluarkan JSON. Artikel ini mengukur yq v4.44.6, PyYAML 6.0.3, dan js-yaml pada sampel 2.39 MB, menjelaskan mengapa ekstensi input menentukan format output, lalu memberi resep yang benar untuk konversi batch, tanda kutip, indentasi, dan presisi bilangan bulat besar.

Menengah±9 menit bacaDiperbarui 2026-11-03