Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

JSON (JavaScript Object Notation) es un formato ligero de intercambio de datos que es fácil de leer y escribir para los humanos, y fácil de parsear y generar para las máquinas. Es un formato de texto que utiliza una sintaxis basada en objetos y arrays de JavaScript.

1Estructura de JSON

Un archivo JSON puede contener un único valor, de los tipos de datos existentes en JavaScript. Es decir, números, strings, booleanos, null, objetos y arrays.

Si bien la sintaxis y los tipos soportados son los de JavaScript, existen equivalencias y/o transformaciones posible con los tipos de Python. A continuación se muestra una tabla de equivalencias:

JavaScriptPython
numberint, float
stringstr
nullNone
objectdict
arraylist

Este formato es muy utilizado para el intercambio de datos entre aplicaciones y servidores, especialmente en la Web, ya que es fácil de parsear y generar en la mayoría de los lenguajes de programación.

{
  "nombre": "Juan",
  "edad": 30,
  "es_estudiante": false,
  "cursos": ["Matemáticas", "Física", "Química"],
  "direccion": {
    "calle": "Calle Falsa 123",
    "ciudad": "Springfield",
    "pais": "USA"
  }
}

En la sección de Persistencia de Datos vimos cómo trabajar con archivos JSON en Python utilizando la librería estándar json. Aquí veremos cómo utilizar JSON para organizar registros en un archivo.

2Organizando registros con JSON

Una forma común de organizar registros en un archivo JSON es utilizar una lista de objetos, donde cada objeto representa un registro. Por ejemplo, si queremos almacenar una agenda de contactos, podemos utilizar la siguiente estructura:

[
  {
    "nombre": "Juan",
    "telefono": "123456789",
    "email": "juan@example.com"
  },
  {
    "nombre": "Ana",
    "telefono": "987654321",
    "email": "ana@example.com"
  }
]

Cada objeto en la lista representa un contacto, con campos para el nombre, teléfono y correo electrónico. Podemos agregar, eliminar o modificar contactos simplemente manipulando la lista de objetos.

En Python, podemos trabajar con este archivo JSON utilizando la librería json de la siguiente manera

3Agenda en formato JSON

A continuación se muestra cómo definir una clase Agenda que almacena los contactos en un archivo .json, junto con su iterador y ejemplos de uso.

import json
import os


class Agenda:
    def __init__(self, archivo):
        self._archivo = archivo

        # Si el archivo no existe, lo crea con una lista vacía
        if not os.path.exists(archivo):
            with open(archivo, "w") as f:
                json.dump([], f)

        # Carga los contactos existentes
        with open(archivo, "r") as f:
            self._contactos = json.load(f)

    def guardar_contacto(self, nombre, telefono="", email=""):
        if not nombre:
            raise ValueError("El nombre es obligatorio")

        contacto = {"nombre": nombre, "telefono": telefono, "email": email}
        self._contactos.append(contacto)

        with open(self._archivo, "w") as f:
            json.dump(self._contactos, f, ensure_ascii=False, indent=2)

    def cantidad_registros(self):
        return len(self._contactos)

    def __iter__(self):
        return AgendaIterator(self)

Definimos el iterador para la agenda:

class AgendaIterator:
    """Iterador para la agenda de contactos en formato JSON"""

    def __init__(self, agenda):
        self._agenda = agenda
        self._index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self._index >= len(self._agenda._contactos):
            raise StopIteration()

        contacto = self._agenda._contactos[self._index]
        self._index += 1
        return contacto

Ejemplo de uso:

agenda = Agenda("agenda.json")
agenda.guardar_contacto("Juan", "123456789", "juan@example.com")
agenda.guardar_contacto("Ana", "987654321", "ana@example.com")
agenda.guardar_contacto("Homero", "555-8765", "")
agenda.guardar_contacto("Lisa", "", "lisa.simpson@example.com")

print(f"Cantidad de registros: {agenda.cantidad_registros()}")

for contacto in agenda:
    print(contacto)
Output
Cantidad de registros: 4
{'nombre': 'Juan', 'telefono': '123456789', 'email': 'juan@example.com'}
{'nombre': 'Ana', 'telefono': '987654321', 'email': 'ana@example.com'}
{'nombre': 'Homero', 'telefono': '555-8765', 'email': ''}
{'nombre': 'Lisa', 'telefono': '', 'email': 'lisa.simpson@example.com'}

Si vemos el contenido del archivo agenda.json, se observa que los datos están guardados en formato de texto legible, seguiendo el estándar JSON

with open("agenda.json", "r") as f:
    contenido = f.read()
    print(contenido)
Output
[
  {
    "nombre": "Juan",
    "telefono": "123456789",
    "email": "juan@example.com"
  },
  {
    "nombre": "Ana",
    "telefono": "987654321",
    "email": "ana@example.com"
  },
  {
    "nombre": "Homero",
    "telefono": "555-8765",
    "email": ""
  },
  {
    "nombre": "Lisa",
    "telefono": "",
    "email": "lisa.simpson@example.com"
  }
]

La principal ventaja de utilizar JSON para organizar registros es que es un formato ampliamente soportado y fácil de leer y escribir. Además, permite almacenar datos estructurados de manera flexible, ya que los objetos pueden tener diferentes campos y tipos de datos.

3.1JSON y bases de datos de documentos (NoSQL)

El formato JSON es la piedra angular de las bases de datos de documentos (como MongoDB), un componente vital en muchos sistemas de recuperación de información modernos Manning et al., 2008. A diferencia de las bases de datos relacionales tradicionales, estas permiten almacenar “objetos” complejos sin un esquema rígido predefinido, facilitando la indexación de datos semi-estructurados.

3.2JSON vs XML en Recuperación de Información

Si bien ambos formatos se utilizan para representar datos semi-estructurados, JSON suele preferirse en entornos web debido a:

A continuación se define una agenda general donde solo los campos nombres y apellidos son obligatorios, y donde cada registro puede tener incluso campos diferentes.

class AgendaGeneral:
    def __init__(self, archivo):
        self._archivo = archivo

        if not os.path.exists(archivo):
            with open(archivo, "w") as f:
                json.dump([], f)

        with open(archivo, "r") as f:
            self._contactos = json.load(f)

    def guardar_contacto(self, **kwargs):
        if "nombre" not in kwargs or "apellido" not in kwargs:
            raise ValueError("Los campos 'nombre' y 'apellido' son obligatorios")

        self._contactos.append(kwargs)

        with open(self._archivo, "w") as f:
            json.dump(self._contactos, f, ensure_ascii=False, indent=2)

    def cantidad_registros(self):
        return len(self._contactos)

    def __iter__(self):
        return AgendaIterator(self)

Ejemplo de uso:

from pprint import pprint


agenda = AgendaGeneral("agenda_general.json")
agenda.guardar_contacto(
    nombre="Juan",
    apellido="Pérez",
    telefono="123456789",
    email="juan.perez@example.com",
)
agenda.guardar_contacto(
    nombre="Ana",
    apellido="García",
    telefono="987654321",
    cumpleaños="1990-01-01"
)
agenda.guardar_contacto(
    nombre="Homero",
    apellido="Simpson",
    direccion={"calle": "742 Evergreen Terrace", "ciudad": "Springfield"},
    telefono="555-8765",
)
agenda.guardar_contacto(
    nombre="Lisa",
    apellido="Simpson",
    email="lisa.simpson@example.com",
    hobbies=["saxofón", "política"],
)
agenda.guardar_contacto(
    nombre="Bart",
    apellido="Simpson",
    telefono="555-1234",
    email="bart.simpson@example.com",
)

for contacto in agenda:
    # Imprime nombre y apellido en la primera línea
    nombre = contacto.get("nombre", "")
    apellido = contacto.get("apellido", "")
    print(f"{nombre} {apellido}")

    # Función recursiva para imprimir campos
    def imprimir_campos(d, indent=4):
        for clave, valor in d.items():
            if clave in ("nombre", "apellido"):
                continue

            print(f"{" " * indent}{clave}:", end="")

            if isinstance(valor, dict):
                print()
                imprimir_campos(valor, indent + 4)
            elif isinstance(valor, list):
                print()
                for item in valor:
                    if isinstance(item, dict):
                        imprimir_campos(item, indent + 4)
                    else:
                        print(f"{" " * (indent + 4)}- {item}")
            else:
                print(f" {valor}")

    imprimir_campos(contacto)
    print()
Output
Juan Pérez
    telefono: 123456789
    email: juan.perez@example.com

Ana García
    telefono: 987654321
    cumpleaños: 1990-01-01

Homero Simpson
    direccion:
        calle: 742 Evergreen Terrace
        ciudad: Springfield
    telefono: 555-8765

Lisa Simpson
    email: lisa.simpson@example.com
    hobbies:
        - saxofón
        - política

Bart Simpson
    telefono: 555-1234
    email: bart.simpson@example.com

Archivo agenda_general.json:

with open("agenda_general.json", "r") as f:
    contenido = f.read()
    print(contenido)

print(f"Cantidad de bytes en el archivo: {len(contenido)}")
print(f"Cantidad de registros: {agenda.cantidad_registros()}")
Output
[
  {
    "nombre": "Juan",
    "apellido": "Pérez",
    "telefono": "123456789",
    "email": "juan.perez@example.com"
  },
  {
    "nombre": "Ana",
    "apellido": "García",
    "telefono": "987654321",
    "cumpleaños": "1990-01-01"
  },
  {
    "nombre": "Homero",
    "apellido": "Simpson",
    "direccion": {
      "calle": "742 Evergreen Terrace",
      "ciudad": "Springfield"
    },
    "telefono": "555-8765"
  },
  {
    "nombre": "Lisa",
    "apellido": "Simpson",
    "email": "lisa.simpson@example.com",
    "hobbies": [
      "saxofón",
      "política"
    ]
  },
  {
    "nombre": "Bart",
    "apellido": "Simpson",
    "telefono": "555-1234",
    "email": "bart.simpson@example.com"
  }
]
Cantidad de bytes en el archivo: 706
Cantidad de registros: 5
References
  1. Manning, C. D., Raghavan, P., & Schütze, H. (2008). Introduction to Information Retrieval. Cambridge University Press. https://nlp.stanford.edu/IR-book/