Probador de JSONPath
Escribe una expresión JSONPath y ve las coincidencias en vivo. Sintaxis RFC 9535.
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
Escribe una expresión JSONPath y ve todas las coincidencias contra tu propio documento, con la ruta normalizada de cada una. Edita y vuelve a ejecutar hasta que seleccione lo que querías.
La sintaxis de aquí sigue la RFC 9535, el estándar propuesto por el IETF publicado en febrero de 2024. Eso importa más de lo que parece, porque durante los diecisiete años anteriores no hubo ninguna especificación.
Por qué hay que declarar el dialecto
JSONPath nació como una entrada de blog de Stefan Goessner en 2007. Se implementó por todas partes y nunca se especificó, y las implementaciones divergieron en casi todo lo interesante: si $.. incluye la raíz, qué significa un índice negativo, si $[0,1] hace unión, cómo se comporta un filtro cuando falta la clave, y qué pasa con un paso de slice igual a cero. Un proyecto de comparación catalogó cientos de esos desacuerdos.
La RFC 9535 lo zanjó. Un probador que no dice qué dialecto implementa te está dando la respuesta sin decirte la pregunta, así que este lo dice: RFC 9535, con las exclusiones que se listan abajo.
Sintaxis admitida aquí
- $
- La raíz del documento. Toda expresión empieza aquí.
- .name y ['name']
- Un miembro con nombre. Usa la forma con corchetes para nombres con espacios o signos de puntuación.
- .* y [*]
- Todos los miembros de un objeto, o todos los elementos de un array.
- ..
- Un segmento descendiente: busca en este nivel y en todos los de abajo.
- [0] y [-1]
- Un índice de array. El negativo cuenta desde el final.
- [1:5], [::2], [::-1]
- Un slice, con la semántica de la RFC 9535. Un paso negativo recorre hacia atrás.
- [0, 2, 'name']
- Varios selectores en un mismo segmento, que producen la unión de sus resultados.
- [?<expresión>]
- Un filtro. Dentro de él, @ es el elemento actual y $ es la raíz del documento. Comparación con == != < <= > >=, combinable con && || y !.
- length() count() match() search() value()
- Las extensiones de función que define la RFC 9535. match() ancla la cadena completa; search() no.
Deliberadamente no admitido
Las expresiones de script con la forma [(...)] nunca se especificaron y la RFC 9535 las eliminó. El operador de padre ^ es una extensión que añadieron algunas implementaciones y que la RFC no incluye. Y @.length como pseudopropiedad es la grafía anterior a la RFC de lo que hoy es length(@); si pegas alguna de estas, el probador te lo dice en vez de devolver nada en silencio.
JSONPath, JMESPath, jq y JSON Pointer
Cuatro formas de direccionar partes de un documento JSON, para cuatro trabajos distintos.
- JSONPath
- Selecciona un conjunto de nodos. Lo mejor cuando quieres todo lo que encaja con un patrón, a cualquier profundidad. Ahora estandarizado como RFC 9535.
- JMESPath
- Además de seleccionar, transforma: proyecciones, multiselect hashes y expresiones con tubería te dejan remodelar la salida. Lo usa la CLI de AWS. Con una especificación de verdad desde el principio.
- jq
- Un lenguaje completo con una sintaxis de consulta encima. Tira de él cuando la operación se parece más a programar que a seleccionar.
- JSON Pointer, RFC 6901
- Direcciona exactamente una ubicación, sin comodines ni filtros. Deliberadamente trivial, y por eso lo usan tanto JSON Patch como JSON Schema. Dos escapes: ~0 para una tilde y ~1 para una barra.
How to do this in code
Ejecutar la misma consulta en código.
py Python
# jsonpath-ng is the most complete Python implementation
from jsonpath_ng.ext import parse
expr = parse('$.store.book[?(@.price < 10)].title')
titles = [m.value for m in expr.find(data)]
# JMESPath, if you prefer a specified language with projections
import jmespath
titles = jmespath.search('store.book[?price < `10`].title', data) js JavaScript
import { JSONPath } from 'jsonpath-plus';
const titles = JSONPath({
path: '$.store.book[?(@.price < 10)].title',
json: data,
});
// Get the normalised paths rather than the values
const paths = JSONPath({ path: '$..author', json: data, resultType: 'path' }); sh jq
jq no tiene un operador de descendiente con filtro, así que las dos mitades se escriben por separado.
# The jq equivalent of a filtered descendant search
jq '.store.book[] | select(.price < 10) | .title' data.json
# Every value at any depth under a key
jq '.. | .author? // empty' data.json java Java
Jayway JsonPath es anterior a la RFC 9535 y difiere de ella en algunos puntos, en especial en los filtros sobre claves ausentes.
import com.jayway.jsonpath.JsonPath;
List<String> titles = JsonPath.read(json, "$.store.book[?(@.price < 10)].title"); Preguntas frecuentes
- ¿Por qué mi expresión no devuelve nada?
- Normalmente por una de tres cosas: un nombre que necesita corchetes con comillas porque contiene un espacio o un guion, un filtro que compara contra una cadena sin comillas (escribe @.type == 'book', no @.type == book), o una ruta que da por hecho un array donde el documento tiene un objeto. El probador reporta un error de parseo con la posición cuando la expresión está mal formada, y un resultado vacío solo cuando la expresión es válida pero no encaja con nada.
- ¿Qué es una ruta normalizada?
- La RFC 9535 define una grafía canónica para la ubicación de una coincidencia: nombres entre corchetes y comillas e índices numéricos, como en $['store']['book'][0]['title']. Cada coincidencia de aquí muestra una, lo que hace que los resultados sean comparables entre implementaciones.
- ¿Es $..* lo mismo que $..?
- No, y esta es una de las divergencias que zanjó la RFC. $..* selecciona todos los nodos descendientes excluyendo la raíz; un $.. suelto no es siquiera una expresión completa.