Update 2013-11-10: I added some edge cases to show the completeness of this format.
Kris Zyp’s jsonpointer is a tool for addressing part of a JSON object, that’s designed to be both powerful and familiar. It supports any value for a key that JSON supports, yet it looks like a path from a URL or a filesystem.
A jsonpointer is the path from the root node of a JSON document to either itself or an interior node. A jsonpointer starts with a “/”. A “/” is also the simplest jsonpointer. After that, it contains one or more keys or indexes (in JavaScript an index is a key, but the JSON spec makes a distinction between keys and indexes), separated by “/” characters. To include a “/” character in a key (JSON supports this), use “~1”. To include a “~” character in a key, use “~0”.
What it lacks are relative paths and home paths (“~”). Since jsonpointer requires that it start with a “/”, this frees me to prepend anything but “/” to the start of the expression. Here are the things I can prepend:
- A dot (.), which makes it a relative path, like “./foo”.
- Two dots (..), which makes it a relative path from the parent node, like “../foo”.
- More than two dots (…), which will go up extra levels. “…/foo” would be analogous to “../../foo” in UNIX file paths. “../../foo” in my augmented json pointer would go to “baz” to quux in this json object: {“foo”: “not here”, “a”: {“b”: {“c”: “baz”}, “..”: {“foo”: “quux”}}} That is, instead of jumping up three levels, it would jump up two levels and interpret the second “..” as a key in a json object. Two dots go up one level, three dots go up two levels, four dots go up three levels, and so on.
- A tilde (~) makes it a path from the home directory.
Some examples of edge cases:
- the absolute path [“.”, “hello”] to access foo in {“.”: {“hello”: “foo”}} will be /./hello
- the relative path [“.”, hello”] to access foo in {“quux”: {“.”: {“hello”: “foo”}}} where the current path is /quux will be “././hello”.
- the relative path [“..”, “baz”] to access “foo” in {“quux”: {“..”: “hello”}, “baz”: “foo”} when where the current path is “/quux” where there is a “..” in the current node will be “../baz”. To access “hello” using a relative path from “/quux”, use “./..”.
While it superficially looks like paths, it’s actually not completely compatible because of the “…” syntax. I think standards that *look* similar but actually have subtle differences are traps for the unwary.
As an alternative, have you seen this proposal for Relative JSON Pointers?? Instead of a dot for each level you go up, it starts with an integer.
Plus it has an interesting JSON-specific feature: if the value following the initial integer is not a JSON Pointer, but actually “#”, then the value returned is the value of the *key or index* that many levels up – so
"0#"
would mean the key/index most directly associated with that data.I wasn’t aware of that. I like it better, and it’s already been submitted. Thanks for pointing it out!