JSON Toolkit

As fronteiras da conversão JSON ↔ YAML e XML

Resumo: A afirmação de que JSON é um subconjunto de YAML só garante uma direção, e o XML não tem mapeamento JSON oficial nenhum — tudo depende de convenção.

Intermediário~12 min de leituraPublicado em 2026-10-30Atualizado em 2026-10-30
Capa de As fronteiras da conversão JSON ↔ YAML e XML

Resumo da ópera: use JSON como formato intermediário: analise a origem em um modelo de dados e depois serialize para o destino; antes de converter, decida se comentários, atributos e namespaces XML e tipos numéricos ou booleanos precisam sobreviver.

Se um pipeline de conversão é utilizável não depende de quão bonita fica a saída, mas de você estar ciente de quanto ele jogou fora.

1. JSON e YAML: contenção unidirecional

A especificação YAML 1.2 diz claramente: JSON é um subconjunto de YAML. Ou seja, qualquer JSON válido é YAML válido:

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

Este trecho é tanto JSON quanto YAML em estilo flow. O inverso não vale.

Recurso JSON YAML 1.2
Comentários ✗ ✓
Âncoras e aliases ✗ ✓
Múltiplos documentos (---) ✗ ✓
Chaves não string ✗ ✓ (1: a, true: b)
Chaves complexas ✗ ✓ (? [a, b])
Sensível à indentação ✗ ✓ (indentação com tabulação é rejeitada)
Inferência de tipo explícita implícita (0o17, 0x1F, .inf)
Legibilidade em uma linha boa ruim (conteúdo longo depende de sintaxe de dobramento)

1.1 A inferência de tipo é a maior armadilha

O YAML interpreta alguns valores que parecem strings como outros tipos:

zip: 01234        # string ou inteiro octal? o schema core do YAML 1.2 trata como string
version: 1.10     # 1.1 (um float); a semântica é perdida
country: NO       # string no YAML 1.2; booleano false no YAML 1.1
date: 2026-10-30  # algumas implementações interpretam como objeto de data

O exemplo NO já queimou muita gente: com um analisador YAML 1.1 (algumas bibliotecas antigas), country: NO vira false. Contramedida: coloque entre aspas todo identificador que "parece número ou booleano", como em version: "1.10".

1.2 Âncoras, aliases e múltiplos documentos

defaults: &defaults
  retries: 3
  timeout: 30

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

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

Depois de expandir as âncoras e converter para JSON você normalmente fica com dois objetos de configuração duplicados, ou com um array (múltiplos documentos precisam virar [{...}, {...}]). De qualquer forma, as âncoras não são restauradas na conversão inversa — essa perda é inevitável.

1.3 Conversão que preserva comentários

A maioria das bibliotecas simplesmente descarta comentários durante a conversão. Quando você precisa mantê-los, use a Document API do pacote yaml:

import { parseDocument } from 'yaml';

const document = parseDocument(`
# Configuração do serviço
port: 8080
`);

document.set('port', 3000);
console.log(document.toString());
// # Configuração do serviço
// port: 3000

O teste é simples: se este arquivo vai ser editado por humanos repetidas vezes, não siga o caminho "analisar → objeto → serializar".

1.4 Como verificar a consistência de ida e volta

/**
 * Verifica a consistência de ida e volta de JSON → YAML → JSON.
 * @param sourceValue Valor JSON original
 * @param stringify Função de serialização YAML
 * @param parse Função de análise YAML
 * @returns Se os dois resultados são exatamente iguais
 */
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);
}

Executá-la com dados reais vale mais do que ler a documentação dez vezes. Garanta que seu conjunto de amostras cubra: null, a string vazia, o array vazio, "00", "1e5", zero negativo, inteiros maiores que 2^53 e strings longas com quebras de linha.

2. JSON e XML: não existe mapeamento padrão

O XML é bem anterior ao JSON e tem capacidades estruturais bem mais fortes (atributos, namespaces, conteúdo misto, DTD). Entre os dois não existe especificação oficial de mapeamento; toda ferramenta faz a mesma coisa: escolhe uma convenção e tenta não perder muito.

2.1 Convenções comuns

Convenção Representação Exemplo
Elemento → chave de objeto Um elemento de mesmo nome virou campo <a>1</a> → {"a": "1"}
Atributo → prefixo @ @name <a id="1"/> → {"a": {"@id": "1"}}
Texto → #text Quando há atributo e texto ao mesmo tempo <a id="1">hi</a> → {"a": {"@id": "1", "#text": "hi"}}
Elemento repetido → array Duas ou mais ocorrências viram array <i>1</i><i>2</i> → {"i": ["1","2"]}
Namespace → prefixo 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 Cinco perdas inevitáveis

  1. Ordem dos elementos: objetos JSON são não ordenados, enquanto XML é uma sequência ordenada de elementos;
  2. Atributos versus elementos filhos: eles carregam semânticas diferentes em XML, mas ambos viram campos simples em JSON;
  3. Conteúdo misto: estruturas como <p>你好 <b>世界</b> 再见</p> não podem ser expressas com um objeto simples;
  4. Declarações de namespace: xmlns é um conceito de escopo; uma vez achatado em campos, o escopo se perde;
  5. CDATA e entidades: <![CDATA[...]]> e &amp; não passam de texto em JSON.

2.3 O dilema de "um elemento ou um array"

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

Com um único item, o xml2js retorna um objeto por padrão e só retorna um array quando há dois. Como resultado, o código do frontend precisa escrever Array.isArray(x) ? x : [x].

Contramedida: habilite a opção "sempre array" ao analisar, ou declare o campo como tipo array com base em um schema.

import { parseStringPromise } from 'xml2js';

const parsed = await parseStringPromise(xmlText, {
  explicitArray: true,   // retorna um array mesmo para um único elemento
  trim: true,
  explicitRoot: false,
});

2.4 Lembrete de segurança

Antes de analisar XML não confiável, você precisa desabilitar entidades externas, caso contrário pode acionar XXE (leitura de arquivos locais, sondagem de redes internas):

// No ecossistema Node, DTDs e entidades externas geralmente são desabilitados por opções do analisador
const parserOptions = { doctype: false, externalEntities: false };

XML → JSON é apenas a primeira camada da conversão; converter não elimina a superfície de ataque que o XML traz.

3. Onde cada um dos três formatos se encaixa

Cenário Formato recomendado Motivo
APIs HTTP públicas JSON Suporte nativo em navegadores e em toda linguagem
Configuração mantida à mão YAML Comentários, indentação, legibilidade
Documentos que precisam de schema forte e namespaces (SOAP, Office Open XML, SVG) XML Capacidades estruturais e o ecossistema existente
Interação com ferramentas operacionais (K8s, CI) YAML Padrão do ecossistema
Persistência, caches, logs JSON / JSONL Universal e sem dependências

4. Notas de implementação

import { stringify as toYaml } from 'yaml';

/**
 * Converte um valor JSON em texto YAML mantendo caracteres chineses sem escape.
 * @param value O valor JSON a converter
 * @returns O texto YAML
 */
function jsonToYaml(value: unknown): string {
  return toYaml(value, {
    indent: 2,
    lineWidth: 0,      // desativa a quebra automática para longas strings não serem divididas
    defaultStringType: 'QUOTE_DOUBLE',
  });
}

Algumas opções práticas:

  • lineWidth: 0 desliga a quebra automática; caso contrário, URLs longas são divididas entre linhas e ficam difíceis de ler;
  • colocar tudo entre aspas duplas evita que valores como NO e 1.10 sejam mal interpretados;
  • para dados com precisão numérica sensível, converta para strings antes de serializar.

Para a direção XML, fixe uma única função de mapeamento e coloque "prefixo de atributo", "nome da chave de texto" e "estratégia de array" na assinatura dela, em vez de espalhá-los por aí:

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

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

5. Lista de verificação

  • [ ] Todo identificador "parecido com número/booleano" em YAML está entre aspas;
  • [ ] Um conjunto de amostras de validação para JSON → YAML → JSON está definido e coberto por testes;
  • [ ] Quando comentários precisam ser preservados, usa-se a Document API em vez de uma ida e volta por objeto;
  • [ ] A convenção de mapeamento XML está documentada e a equipe compartilha um único conjunto de parâmetros;
  • [ ] DTDs e entidades externas estão desabilitados ao analisar XML não confiável;
  • [ ] Contagens de bytes e de campos são comparadas antes e depois da conversão, e qualquer anomalia gera um alerta.

Perguntas frequentes

Como escolher a direção de conversão entre JSON, YAML e XML?

Prefira JSON como formato intermediário: analise YAML e XML em um modelo de dados primeiro e depois serialize a partir desse modelo em vez de reescrever texto. Use a Document API do YAML quando comentários precisarem sobreviver e fixe uma convenção de mapeamento XML antes de precisar de atributos ou namespaces.

Por que a conversão XML para JSON perde atributos e namespaces?

O JSON não tem conceito de atributos ou namespaces, então atributos XML, prefixos e URIs de namespace precisam ser dobrados em chaves comuns, normalmente com prefixo @ ou um nó #text. Quando as regras de mapeamento divergem, o mesmo XML produz JSON diferente e não pode fazer ida e volta.

Devo manter JSON, YAML e XML em sincronia bidirecional de longo prazo?

Não. Comentários, âncoras, atributos XML e namespaces são perdidos entre formatos, e a sincronia bidirecional vai acumulando diferenças. Escolha um formato de origem e trate os outros como exportações pontuais ou visões temporárias.

Referências

Artigos relacionados

Convertendo JSON de e para CSV e dados tabulares

CSV é bidimensional, JSON tem forma de árvore. A parte difícil da conversão não é o código — é decidir de antemão como os arrays serão achatados e como os tipos serão preservados.

Iniciante~10 min de leituraAtualizado em 2026-10-30

Gerenciando JSON para configuração, fixtures e dados locais

A configuração precisa ser em camadas e validada; as fixtures precisam ser determinísticas, legíveis e comparáveis por diff. Se esses dois tipos de arquivo forem mal administrados, o custo de depuração fica alto por muito tempo.

Iniciante~10 min de leituraAtualizado em 2026-10-30

JSON para YAML na linha de comando: as quatro armadilhas por trás de um comando yq

O comando mais copiado dos tutoriais, yq -P input.json > output.yaml, ainda produz JSON no yq v4. Este artigo mede yq v4.44.6, PyYAML 6.0.3 e js-yaml em uma amostra de 2.39 MB, explica por que a extensão da entrada decide o formato de saída e mostra as escritas corretas para conversão em lote, aspas, indentação e precisão de inteiros grandes.

Intermediário~9 min de leituraAtualizado em 2026-11-03