¿Qué es JSONPath?
JSONPath es un lenguaje de consulta para extraer valores de documentos JSON. Propuesto originalmente por Stefan Goessner en 2007 como análogo a XPath para XML, JSONPath permite escribir expresiones como $.store.book[*].author para seleccionar todos los campos de autor dentro de un array de libros sin escribir bucles ni código de recorrido manual. El lenguaje fue estandarizado en febrero de 2024 como RFC 9535, publicado por el IETF.
Una expresión JSONPath siempre comienza con $ que representa la raíz del documento. A partir de ahí se encadenan selectores: notación de punto para claves de objetos, notación de corchetes para índices de arrays, comodines para todos los hijos, y el operador de descenso recursivo (..) para buscar en cada nivel del anidamiento. Las expresiones de filtro como [?(@.price < 10)] permiten seleccionar elementos según condiciones evaluadas sobre sus valores.
JSONPath se usa en herramientas de prueba de APIs como Postman, plataformas de observabilidad como Datadog y Splunk, motores de flujos de trabajo como Apache NiFi, y bibliotecas de programación en JavaScript, Python, Go, Java y C#. Probar las expresiones sobre datos reales antes de integrarlas en código o archivos de configuración evita fallos silenciosos cuando la estructura JSON no coincide con las suposiciones.
¿Por qué usar este Evaluador JSONPath?
Escribir expresiones JSONPath a mano es propenso a errores. Un punto faltante, el tipo de corchete incorrecto o una sintaxis de filtro errónea pueden devolver resultados vacíos sin ningún mensaje de error. Esta herramienta te ofrece retroalimentación visual inmediata sobre lo que coincide con tu expresión.
Casos de Uso de JSONPath
Referencia de Sintaxis JSONPath
RFC 9535 define la sintaxis estándar de JSONPath. La tabla siguiente cubre los operadores que usarás en la mayoría de las consultas. Todas las expresiones comienzan con $ (el nodo raíz) y encadenan uno o más selectores para navegar por la estructura del documento.
| Operador | Descripción | Ejemplo |
|---|---|---|
| $ | Root element | $.store |
| .key | Child property | $.store.book |
| [n] | Array index (zero-based) | $.store.book[0] |
| [*] | All elements in array/object | $.store.book[*] |
| .. | Recursive descent | $..author |
| [start:end] | Array slice | $.store.book[0:2] |
| [?()] | Filter expression | $.store.book[?(@.price<10)] |
| @ | Current node (inside filter) | $.store.book[?(@.isbn)] |
JSONPath vs jq vs XPath
JSONPath, jq y XPath resuelven el mismo problema (consultar datos estructurados) para diferentes formatos y casos de uso. JSONPath apunta a JSON y está disponible como biblioteca en la mayoría de los lenguajes. jq es una herramienta CLI independiente con su propio lenguaje de filtros Turing-completo. XPath opera sobre XML y forma parte del stack de especificaciones del W3C.
| Característica | JSONPath | jq | XPath |
|---|---|---|---|
| Formato de datos | JSON | JSON | XML |
| Acceder al primer elemento | $.store.book[0] | .store.book[0] | /store/book[1] |
| Búsqueda recursiva | $..price | .. | .price? | //price |
| Expresión de filtro | [?(@.price<10)] | select(.price < 10) | [price<10] |
| Especificación | RFC 9535 | stedolan.github.io | W3C XPath 3.1 |
Ejemplos de Código
Cómo evaluar expresiones JSONPath en los lenguajes y herramientas más populares. Cada ejemplo usa la misma estructura JSON de librería para facilitar la comparación.
import { JSONPath } from 'jsonpath-plus';
const data = {
store: {
book: [
{ title: 'Moby Dick', price: 8.99 },
{ title: 'The Great Gatsby', price: 12.99 }
]
}
};
// Get all book titles
JSONPath({ path: '$.store.book[*].title', json: data });
// → ['Moby Dick', 'The Great Gatsby']
// Recursive descent — find every price in the document
JSONPath({ path: '$..price', json: data });
// → [8.99, 12.99]
// Filter — books under $10
JSONPath({ path: '$.store.book[?(@.price < 10)]', json: data });
// → [{ title: 'Moby Dick', price: 8.99 }]from jsonpath_ng.ext import parse
import json
data = {
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}
# Get all book titles
expr = parse("$.store.book[*].title")
titles = [match.value for match in expr.find(data)]
# → ['Moby Dick', 'The Great Gatsby']
# Recursive descent — all prices
expr = parse("$..price")
prices = [match.value for match in expr.find(data)]
# → [8.99, 12.99]
# Filter — books under $10
expr = parse("$.store.book[?price < 10]")
cheap = [match.value for match in expr.find(data)]
# → [{"title": "Moby Dick", "price": 8.99}]package main
import (
"fmt"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
)
func main() {
src := `{
"store": {
"book": [
{"title": "Moby Dick", "price": 8.99},
{"title": "The Great Gatsby", "price": 12.99}
]
}
}`
obj, _ := oj.ParseString(src)
// Get all book titles
expr, _ := jp.ParseString("$.store.book[*].title")
results := expr.Get(obj)
fmt.Println(results)
// → [Moby Dick The Great Gatsby]
// Recursive descent — all prices
expr2, _ := jp.ParseString("$..price")
fmt.Println(expr2.Get(obj))
// → [8.99 12.99]
}# jq uses its own syntax, not JSONPath, but solves the same problem.
# Mapping common JSONPath patterns to jq:
# $.store.book[*].title → get all titles
echo '{"store":{"book":[{"title":"Moby Dick"},{"title":"Gatsby"}]}}' | \
jq '.store.book[].title'
# → "Moby Dick"
# → "Gatsby"
# $..price → recursive descent for "price" keys
echo '{"a":{"price":1},"b":{"price":2}}' | \
jq '.. | .price? // empty'
# → 1
# → 2
# Filter: books where price < 10
echo '{"store":{"book":[{"title":"A","price":8},{"title":"B","price":12}]}}' | \
jq '.store.book[] | select(.price < 10)'
# → {"title":"A","price":8}