Comparar JSON
Compara dos documentos por estructura: reformatear o cambiar el orden de las claves no cuenta.
Nada de lo que pegues sale de tu navegador. La lista de permitidos de connect-src convierte eso en una garantía del navegador, no en una promesa. Compruébalo tú mismo
Esto compara dos documentos por estructura y no por líneas. Reformatea uno de ellos, ordena sus claves, cambia su indentación: el diff sigue vacío, porque nada de eso cambió los datos.
Un diff de texto sobre JSON es casi inútil justo por esa razón. Reserializa un documento con otra biblioteca y todas las líneas aparecerán como modificadas sin que nada haya cambiado de verdad.
Qué cuenta como diferencia
Cuatro tipos de cambio, cada uno reportado con un JSON Pointer a la ubicación exacta.
- Añadido
- Una clave o elemento presente a la derecha y no a la izquierda.
- Eliminado
- Presente a la izquierda y no a la derecha.
- Modificado
- Presente en ambos con un valor distinto del mismo tipo.
- Cambio de tipo
- Presente en ambos con un tipo distinto. Merece la pena separarlo, porque un número que ha pasado a ser cadena suele ser un fallo de serialización y no un cambio de datos.
Cómo se comparan los arrays, y por qué importa
Los arrays son la parte difícil de cualquier diff estructural, y no hay una única respuesta correcta.
Comparar posición a posición es correcto para una tupla de forma fija y catastrófico para una lista. Inserta un elemento al principio de un array de mil elementos y todas las posiciones posteriores se reportarán como modificadas, lo que entierra la única diferencia real bajo mil falsas.
Esta herramienta hace en su lugar una pasada de subsecuencia común más larga, así que una inserción se reporta como inserción. Eso cuesta un tiempo proporcional al producto de las dos longitudes, así que por encima de un umbral pasa a comparación posicional y lo dice en las notas. Nunca se degrada en silencio.
Cosas que a propósito no son diferencias
- El orden de las claves
- Los objetos JSON no tienen orden según la especificación. Dos documentos con los mismos miembros en distinto orden son el mismo documento.
- Espacios e indentación
- No significativos para un parser, así que invisibles aquí.
- 0 y -0
- Distintos bajo Object.is pero idénticos como números JSON.
How to do this in code
Comparación estructural en código.
sh jq
La primera línea es la que hay que recordar. Ordenar las claves primero elimina casi todo el ruido de un diff de texto.
# Sort keys recursively, then diff the text. Cheap and
# surprisingly effective for small documents.
diff <(jq -S . a.json) <(jq -S . b.json)
# Keys present in one and not the other
jq -n --slurpfile a a.json --slurpfile b b.json \
'($a[0] | paths) - ($b[0] | paths)' py Python
from deepdiff import DeepDiff
diff = DeepDiff(a, b, ignore_order=True)
print(diff)
# Standard library only, for a shallow comparison
changed = {k for k in a.keys() | b.keys() if a.get(k) != b.get(k)} js JavaScript
JSON Patch es el formato estándar para transmitir un diff de JSON, y sus rutas son punteros RFC 6901 como los que reporta esta herramienta.
import { compare } from 'fast-json-patch';
// RFC 6902 JSON Patch: a list of operations that turns a into b
const patch = compare(a, b);
// [{ op: 'replace', path: '/user/name', value: 'Priya' }] go Go
go-cmp es la opción estándar en los tests de Go y produce una salida legible para estructuras anidadas.
import "github.com/google/go-cmp/cmp"
if d := cmp.Diff(a, b); d != "" {
t.Errorf("mismatch (-want +got):\n%s", d)
} Preguntas frecuentes
- ¿Por qué reordenar las claves no muestra ninguna diferencia?
- Porque la RFC 8259 define un objeto como una colección sin orden. En la práctica todos los parsers conservan el orden de inserción, y los diffs que dependen de él están comprobando la serialización y no los datos.
- ¿Puedo ignorar campos como las marcas de tiempo?
- Sí. Ignorar una ruta la saca por completo de la comparación, que es como se comparan dos respuestas de API que solo difieren en requestId y generatedAt.
- ¿Qué es un JSON Pointer?
- La RFC 6901: una ruta separada por barras como /users/0/email. Dentro de una clave hay dos caracteres que necesitan escape: ~ pasa a ~0 y / pasa a ~1. Cada cambio reportado aquí lleva uno, así que puedes direccionar la ubicación mediante código.