JSON es ac­tua­l­me­n­te uno de los formatos más im­po­r­ta­n­tes para in­te­r­ca­m­biar datos entre apli­ca­cio­nes, es­pe­cia­l­me­n­te online. JSONPath es un lenguaje de expresión que puede uti­li­zar­se para leer datos es­pe­cí­fi­cos de objetos JSON. Aquí veremos la im­ple­me­n­ta­ción de JSONPath en Python y cómo uti­li­zar­lo gracias a ejemplos sencillos de entender.

¿Qué es Python JSONPath?

JSON es un formato de archivo mu­l­ti­si­s­te­ma que puede uti­li­zar­se para facilitar el in­te­r­ca­m­bio de datos es­tru­c­tu­ra­dos entre apli­ca­cio­nes. Los archivos JSON están formados por pares clave-valor enu­me­ra­dos. Los valores pueden aceptar distintos tipos de datos, tanto valores pri­mi­ti­vos como objetos. Los objetos, a su vez, pueden contener sus propios pares clave-valor. Como casi todos los sistemas actuales reconocen JSON, puede uti­li­zar­se para el in­te­r­ca­m­bio de datos entre cualquier tipo de apli­ca­ción, tanto lo­ca­l­me­n­te en el equipo como a través de Internet.

Pero no todas las apli­ca­cio­nes necesitan capturar todos sus datos en un archivo JSON. En estos casos, JSONPath es una buena opción. JSONPath es un lenguaje de expresión que puede uti­li­zar­se para leer in­fo­r­ma­ción es­pe­cí­fi­ca de objetos JSON. En la mayoría de los lenguajes de pro­gra­ma­ción, JSONPath debe im­po­r­tar­se de una librería externa. Dado que estas librerías deben im­ple­me­n­tar­se por separado para cada lenguaje, las librerías o im­ple­me­n­ta­cio­nes pueden presentar pequeñas di­fe­re­n­cias.

El módulo jsonpath-ng de Python

“jsonpath-ng” es pro­ba­ble­me­n­te la im­ple­me­n­ta­ción más común de JSONPath en Python. También hay otras im­ple­me­n­ta­cio­nes de JSONPath en Python, como “jsonpath” y “jsonpath-rw”. No obstante, estas son menos fre­cue­n­tes y completas, así que aquí nos ce­n­tra­re­mos ex­clu­si­va­me­n­te en “jsonpath-ng”.

In­s­ta­la­ción

Puedes instalar “jsonpath-ng” muy fá­ci­l­me­n­te desde tu shell. Si­m­ple­me­n­te empieza in­tro­du­cie­n­do el comando “pip install jsonpath-ng”.

Nota

La in­s­ta­la­ción se realiza mediante el gestor de paquetes pip, que se utiliza por defecto para Python. En caso de que no tengas instalado este gestor de paquetes, tendrás que de­s­ca­r­gar­lo primero. Puedes encontrar más in­fo­r­ma­ción en la página web de Pip.

Sintaxis

JSONPath puede uti­li­zar­se para ejecutar consultas complejas sobre objetos JSON. Hay varios métodos, ope­ra­do­res y ex­pre­sio­nes atómicas en el módulo que pueden uti­li­zar­se para se­le­c­cio­nar y consultar datos es­pe­cí­fi­cos. Los dos métodos JSONPath más im­po­r­ta­n­tes son “parse()” y “find()”. Con “parse()” puedes definir consultas, que luego se pueden re­fe­re­n­ciar y repetir tantas veces como quieras. Con “find()” puedes ejecutar estas consultas sobre datos JSON para extraer valores concretos. En el siguiente ejemplo se explica con más detalle.

import json
import jsonpath_ng as jp
raw_data = '''
{
    "name": "John",
    "age": 30,
    "place of residence": "New York"
}
'''
json_object = json.loads(raw_data)
name_query = jp.parse("$.name")
result = name_query.find(json_object)
print(result[0].value) # output: John
Python

En el ejemplo anterior, los datos JSON en forma de cadena se co­n­vi­r­tie­ron en un objeto di­c­cio­na­rio uti­li­za­n­do “json.loads”. Este es el formato con el que Python funciona mejor. Al crear “name_query”, se definió la petición ““$.name“”, que debía devolver el valor de “name”. A co­n­ti­nua­ción, se aplicó al objeto JSON con “find()”. El resultado de la petición se al­ma­ce­na­ba en la variable “result” y se leía con “result[0].value”.

Nota

Para que Python pueda leer datos JSON de una cadena o de un archivo JSON, hay que incluir el módulo de Python “json”, como en el ejemplo anterior. A partir de ahí, las cadenas y los archivos pueden co­n­ve­r­ti­r­se a un formato legible por Python mediante “loads()” o “load()”.

El método find no solo devuelve el valor so­li­ci­ta­do, sino también otra in­fo­r­ma­ción co­n­te­x­tual, como la ruta al valor buscado. Esta in­fo­r­ma­ción se devuelve en forma de lista, donde el valor que se está buscando tiene un índice 0. Ahora puedes utilizar “result[0].value” para obtener el valor que estás buscando.

En el ejemplo anterior, se utilizó el signo de dólar al es­ta­ble­cer la petición. Se trata de una expresión atómica que se utiliza para referirse al objeto raíz del JSON. Todos los ope­ra­do­res y ex­pre­sio­nes atómicas se enumeran en la siguiente tabla.

Expresión/Operador Si­g­ni­fi­ca­do Ejemplo Ex­pli­ca­ción
$ Objeto raíz $.marcus.age Busca el valor de la clave “age” el objeto “marcus”.
. Ámbito de un objeto $.marcus Busca “marcus”, donde “marcus” es un campo del objeto raíz.
.. Búsqueda re­cu­rre­n­te de un campo. También se buscan los campos de los su­bo­b­je­tos. $.people..age Devuelve todas las apa­ri­cio­nes del campo “age” en personas y sus su­bo­b­je­tos.
[x] Elemento de una matriz $.people[5] Busca el sexto elemento (en el índice 5) en la matriz “people”.
\* Marcador de posición numérico, utilizado sobre todo en relación con los bucles for-loop ‘$.people[*]’ Busca un campo en “people”. Combinado con un for-loop, cada campo se devuelve su­ce­si­va­me­n­te.

Además de ex­pre­sio­nes y ope­ra­do­res, existen filtros que puedes utilizar para que tu búsqueda sea aún más es­pe­cí­fi­ca. En la im­ple­me­n­ta­ción Python de JSONPath, estos filtros pueden eje­cu­tar­se con ope­ra­do­res Python. Todos los símbolos que se pueden utilizar con filtros se muestran con ejemplos en la siguiente tabla.

Símbolos Si­g­ni­fi­ca­do Ejemplo Ex­pli­ca­ción
.[?(filter)] Sintaxis general de los filtros. Se pueden omitir los pa­ré­n­te­sis redondos. $.people[?(@.name == "Anne")] Busca personas cuyo nombre sea “Anne”.
@ Objeto que se está buscando ac­tua­l­me­n­te, a menudo se utiliza en relación con los bucles for-loop. $.people[?(@.age < 50)] Busca campos en “people” cuyo valor para “age” sea inferior a 50.
<, >, <=, >=, == und != Ope­ra­do­res de co­m­pa­ra­ción que pueden uti­li­zar­se para filtrar re­su­l­ta­dos de búsqueda es­pe­cí­fi­cos. $.people[@.age < 50 & @.age > 20] Busca personas que tengan entre 20 y 50 años.
& Logical AND. $.people[?(@.place of residence == Newark & @.age > 40)] Busca personas mayores de 40 años que vivan en Newark.
Nota

Si quieres utilizar filtros, tienes que incluir el módulo “jsonpath_ng.ext” y re­fe­re­n­ciar­lo al llamar a “parse()”.

Caso práctico de Python JSONPath

import json
import jsonpath_ng as jp
# JSON data as string
import json
import jsonpath_ng as jp
# JSON data as string
data = """
{
    "cities": [
        {
            "name": "Trenton",
            "state": "New Jersey",
            "residents": 90048,
            "iscapital": true,
            "neighborhood Central West": {
                "residents": 1394    
            }
        },
        {
            "name": "Hamburg",
            "state": "Hamburg",
            "residents": 1841000,
            "iscapital": false
        },
        {
            "name": "New York City",
            "state": "New York",
            "residents ": 8804190
            "iscapital": false
        },
        {
            "name": "Los Angeles",
            "state": "California",
            "residents": 3898767
        }
    ]
}
"""
# Convert data from String to dictionary
json_data = json.loads(data)
# Inquiry: Names of all cities
query1 = jp.parse("cities[*].name")
for match in query1.find(json_data):
    print(match.value)     # output: Trenton, Hamburg, New York City, Los Angeles
# jsonpath_ng.ext import to apply filters
import jsonpath_ng.ext as jpx
# Anfrage: Names of all cities with less than 1.5 million residents 
query2 = jpx.parse("$.cities[?@.residents < 1500000].name")
for match in query2.find(json_data):
    print(match.value)     # output: Trenton
# All fields labeled “residents” 
query3 = jp.parse("$.cities..residents")
match = query3.find(json_data)
for i in match:
    print(i.value)     # output: 1394, 1841000, 8804190, 3898767
# The names of all cities that are not called “Trenton”
query4 = jpx.parse('$.cities[?(@.name != "Trenton")].name')
for match in query4.find(json_data):
    print(match.value)     # output: Hamburg, New York City, Los Angeles
Python

En este ejemplo, los datos JSON se es­pe­ci­fi­can como una cadena y luego se co­n­vie­r­ten en un objeto di­c­cio­na­rio mediante “loads()”. Solo hay una matriz en el objeto raíz, que a su vez contiene 4 ciudades. Cada ciudad tiene 4 campos que contienen los si­guie­n­tes datos:

  • Nombre de la ciudad
  • Estado de la ciudad
  • Número de ha­bi­ta­n­tes
  • Si la ciudad es capital o no

New Jersey tiene como campo adicional el llamado “Central West”, que también tiene un número de ha­bi­ta­n­tes.

Una vez co­n­ve­r­ti­dos los datos a un formato adecuado, se ejecutan cuatro consultas di­fe­re­n­tes. Sus funciones y re­su­l­ta­dos se dejan como co­me­n­ta­rios en el ejemplo. Puedes observar que en la tercera consulta aparecen cinco valores. Esto se debe a que el operador “..” busca de forma re­cu­rre­n­te los campos coin­ci­de­n­tes. Esto significa que se buscan todos los objetos, así como todos los hijos de estos objetos. De este modo, el número de ha­bi­ta­n­tes de Central West aparece junto al número de ha­bi­ta­n­tes de las ciudades.

Consejo

JSON y Python, co­m­bi­na­dos, co­n­s­ti­tu­yen una he­rra­mie­n­ta realmente potente para la pro­gra­ma­ción en Internet. Si tienes una apli­ca­ción web que quieras publicar de forma rápida, sencilla y di­re­c­ta­me­n­te desde Git, Deploy Now de IONOS podría ser la solución perfecta.

Ir al menú principal