JSON pointer: Difference between revisions
Content added Content deleted
Line 457: | Line 457: | ||
error: "bad/pointer" pointers must start with a slash or be the empty string |
error: "bad/pointer" pointers must start with a slash or be the empty string |
||
</pre> |
</pre> |
||
=={{header|jq}}== |
|||
{{works with|jq}} |
|||
'''Also works with gojq, the Go implementation of jq.''' |
|||
The approach taken here is to piggy-back off jq's support for "array paths", that is, |
|||
JSON arrays of strings and integers representing paths in much the same way as JSON Pointer. |
|||
Note that jq's `getpath/1` cannot be used directly as it does not raise errors in the way required of JSON Pointer. |
|||
<syntaxhighlight lang="jq"> |
|||
# JSON Pointer |
|||
# The characters '~' (%x7E) and '/' (%x2F) have special meanings in JSON Pointer, |
|||
# so '~' needs to be encoded as '~0' |
|||
# and '/' needs to be encoded as '~1' |
|||
# when these characters appear in a reference token. |
|||
# The JSON Pointer spec allows 0 both for indexing an array and for retrieving a key named "0". |
|||
# disambiguate($k) accordingly disambiguates $k w.r.t. `.`. |
|||
# $k should be a string or integer. |
|||
# If $k is a string and . is an object then: if has($k) then $k else null end. |
|||
# If $k is an integer and . is an array, then emit $k. |
|||
# If $k is an integer-valued string and . is an array then exit $k|tonumber. |
|||
# Otherwise emit null |
|||
def disambiguate( $k ): |
|||
if ($k|type) == "string" |
|||
then if type == "object" then $k |
|||
elif type == "array" and ($k|test("^[0-9]+$")) |
|||
then ($k|tonumber) |
|||
else null |
|||
end |
|||
elif ($k|type) == "number" and type == "array" |
|||
then $k |
|||
else null |
|||
end; |
|||
# $array should be an array of strings and integers. |
|||
# Emit the disambiguated array, suitable for running getpath/1. |
|||
# Emit null if disambiguation fails at any point. |
|||
def disambiguatePath($array): |
|||
. as $in |
|||
| reduce $array[] as $x ([]; |
|||
if . then . as $path |
|||
| ($in | getpath($path) | disambiguate($x)) as $y |
|||
| if $y then . + [ $y ] |
|||
else null |
|||
end |
|||
else . |
|||
end); |
|||
# $p is an array as for getpath |
|||
def stepwisegetpath($p): |
|||
if ($p|length) == 0 then . |
|||
else $p[0] as $x |
|||
| if (type == "object" and ($x|type) == "string" and has($x)) |
|||
or (type == "array" and ($x|type) == "number" and $x > -1 and $x < length) |
|||
then .[$x] | stepwisegetpath($p[1:]) |
|||
else "JSON Pointer mismatch" | error |
|||
end |
|||
end; |
|||
# getjsonpointer() is like jq's getpath() but for jsonpointer pointers, |
|||
# and an error condition is raised if there is no value at the location. |
|||
def getjsonpointer($pointer): |
|||
if $pointer == "" then . |
|||
elif $pointer[:1] != "/" then "Invalid JSON Pointer: \($pointer)" | error |
|||
else . as $in |
|||
# first decode ~1, then ~0 |
|||
| ($pointer | split("/") | .[1:] |
|||
| map(gsub("~1"; "/") | gsub("~0"; "~"))) as $array |
|||
| disambiguatePath($array) as $apath |
|||
| if $apath then stepwisegetpath($apath) |
|||
else "JSON Pointer disambiguation failed: \($pointer)" | error |
|||
end |
|||
end; |
|||
</syntaxhighlight> |
|||
The Task |
|||
<syntaxhighlight lang="jq"> |
|||
def check($p; $result): |
|||
if getjsonpointer($p) == $result |
|||
then empty |
|||
else "whoops: \($p)" |
|||
end; |
|||
def checkError($p): |
|||
(try getjsonpointer($p) catch nan) |
|||
| . as $result |
|||
| if isnan then empty |
|||
else "\($p) should have raised an error but yielded \($result)" |
|||
end; |
|||
check(""; .), # The entire input document. |
|||
check("/"; "Rosetta"), |
|||
check("/ "; "Code"), |
|||
check("/abc"; ["is", "a"]), |
|||
check("/def/"; "programming"), |
|||
check("/g~1h"; "chrestomathy"), |
|||
check("/i~0j"; "site"), |
|||
check("/wiki/links/0"; "https://rosettacode.org/wiki/Rosetta_Code"), |
|||
check("/wiki/links/1"; "https://discord.com/channels/1011262808001880065"), |
|||
checkError("/wiki/links/2"), |
|||
checkError("/wiki/name"), |
|||
checkError("/no/such/thing"), |
|||
checkError("bad/pointer") |
|||
</syntaxhighlight"> |
|||
{{output}} |
|||
Nothing, by design. |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |