← All ivy-nodes
IVYXSTUDIO · IVY NODE
J
JSON Extract
ivy.node.json-extract · v0.1.0
ivyx✓
Reads one value out of a JSON document by dotted path and reports whether it was found. Segments split on a dot, an integer segment indexes a list, and a path that does not exist yields the supplied default with found set to false rather than raising — so the same node answers both 'give me this field' and 'does this field exist'. Pure compute: no network, no file access.
#json#extract#path
Inputs
| Field | Type | Description |
|---|---|---|
| sourcerequired | Not declared | The JSON document: text to parse, or an already-decoded object or array. Deliberately UNTYPED: the gateway's validator compares a declared type array by stringifying it, so `["string","object","array"]` refuses every value with `expected type "string,object,array"` — measured 2026-09-30. An undeclared type accepts all three, and the cell checks the shape itself. |
| pathrequired | string | Dotted path, e.g. `choices.0.message.content`. |
| default | Not declared | Returned when the path is absent. Null when omitted. |
Outputs
| Field | Type | Description |
|---|---|---|
| valuerequired | Not declared | The value at the path, or the default. |
| foundrequired | boolean | False when the path was absent and the default was used. |
Source
python
# Input preparation
inp = __ivy_ctx__["nodes"][__ivy_node_id__]["input"]
source = inp["source"]
path = inp["path"]
default = inp.get("default")
# Compute
import json as _json
from typing import Any
_MISSING = object()
def _parse(source: Any) -> Any:
"""A JSON string is parsed; anything already decoded is used as it is."""
if isinstance(source, (dict, list)):
return source
if isinstance(source, str):
try:
return _json.loads(source)
except _json.JSONDecodeError as exc:
raise ValueError(f"source is not valid JSON: {exc.msg}") from None
raise ValueError("source must be a JSON string, object or array")
def _step(node: Any, key: str) -> Any:
"""One segment. A list takes an integer index, a dict takes a key."""
if isinstance(node, list):
try:
index = int(key)
except ValueError:
return _MISSING
return node[index] if -len(node) <= index < len(node) else _MISSING
if isinstance(node, dict):
return node.get(key, _MISSING)
return _MISSING
def extract(source: Any, path: str, default: Any = None) -> Any:
"""
Read one value out of a JSON document by dotted path.
Segments are split on `.`; a segment that is an integer indexes a list,
so `items.0.name` and `items[0].name` describe the same place — the
brackets are stripped rather than parsed, because a second syntax for
one idea is a second thing to get wrong.
A path that does not exist returns `default` instead of raising: a
missing field is the ordinary case when reading somebody else's JSON,
and a node that raises on it cannot be used to check whether a field is
there.
"""
if not isinstance(path, str) or not path.strip():
raise ValueError("path is required")
document = _parse(source)
node: Any = document
for segment in path.replace("[", ".").replace("]", "").split("."):
if segment == "":
continue
node = _step(node, segment)
if node is _MISSING:
return default, False
return node, True
value, found = extract(source, path, default)
# Output collection (runner reads __ivy_ctx__)
out = __ivy_ctx__["nodes"][__ivy_node_id__]["output"]
out["value"] = value
out["found"] = foundTests
Requires: python:3.9
- nested-list
A path through a list index returns the exact string at that place.
- bracket-syntax
Bracket indexing describes the same place as a dotted integer.
- absent-path
A path that is not there yields the default and found false, without raising.
- invalid-json
Text that is not JSON is an error, not a silent default.