Problem statement

Using Elisp, when point is on an element in a JSON datastructure (either raw JSON or an Elisp sexp of the kind generated by json.el), is there an easy way to get a json-pointer-get-style path to that element?

Sexp example

To take the example from the json-pointer.el docs:

(let ((json '((foo . 1)
              (bar . [((qux . "hello")) 3])
              (baz . ((boo . [1 3 5 7]))))))
    (json-pointer-get json "/foo")        ;; => 1
    (json-pointer-get json "/bar/0")      ;; =>  '((qux . "hello"))
    (json-pointer-get json "/bar/0/qux")  ;; => "hello"
    (json-pointer-get json "/bar/1")      ;; => 3
    (json-pointer-get json "/baz/boo/2")) ;; => 55

If point was on the "1" on the first line, I'd like to get "/foo".

If point was on the first opening parenthesis or last closing parenthesis inside the square brackets of the second line, I'd like to get "/bar/0".

If point was somewhere on "hello", I'd like to get "/bar/0/qux".

If point was on the "3" on the second line, I'd like to get "/bar/1".

And if point was on the "5" on the third line, I'd like to get "/baz/boo/2".

Raw JSON example

I'd also like to get the same paths when point is positioned on the same elements in raw JSON format instead of an Elisp sexp.

In other words, if my buffer contained the raw JSON equivalent of the above sexp:

{"foo":1, "bar":[{"qux":"hello"}, 3], "baz":{"boo":[1, 3, 5, 7]}}

If point was on the first "1", I'd like to get "/foo".

If point was on the opening or closing curly braces following "bar", I'd like to get "/bar/0".

If point was somewhere on "hello", I'd like to get "/bar/0/qux".

If point was on the "3" in the second element of "bar", I'd like to get "/bar/1".

And if point was on the "5", I'd like to get "/baz/boo/2".

Naturally, this should work regardless of the whitespace and should work just as well if everything was one one line or spread across multiple lines.

  • I just found json-snatcher, which seems to do something like what I need, but it has two problems. First, it only returns paths for some elements but not others. Second, the format of the path it returns is different from what I need. The second problem should be relatively trivial to fix, as I should be able to just munge the format to what I need. The first problem is relatively major, though, and I'm not sure how to fix it.
    – izkon
    Oct 13 '18 at 23:41

I've just finished implementing such functionality in my json-mode, which can generate JSON paths in multiple formats, including JSON pointer (RFC 6901).

After installing, to get JSON pointer paths, you'll need to add following to your init file (or use customize-group):

(setq json-mode-path-format #'json-mode-format-path-json-pointer)

After that, you'll be able to get the JSON path to thing at point by typing C-c C-l in json-mode. The path will be copied to your kill ring.

  • Thank you for your hard work. Though this only works with raw JSON and not with sexps of the kind generated by json.el, as far as I can see, and so is only half an answer to my question, I will accept your answer as it's the closest one yet to what I need. It does have some issues, though: first, when pasting the above JSON test in to a new buffer and activating json-mode, it tells me "Invalid JSON", though running json-mode-validate-buffer tells me "Buffer contains a valid JSON". Also, when point is on "hello", I should get "/bar/0/qux" but I get only "/bar/0".
    – izkon
    Nov 11 '18 at 10:07
  • I can't reproduce either of your problems. An empty buffer doesn't contain a valid JSON, so the error makes sense, and your example with /bar/0/qux seems to work flawlessly for me. Have you tried updating json-mode to the newest version?
    – user12563
    Nov 11 '18 at 11:52
  • I'm not reporting that an empty buffer results in an error message saying that it's not valid JSON. Rather, I'm reporting that if I (1) create an empty buffer (with M-x switch-to-buffer <RETURN> foo and then (2) fill that buffer with the JSON example in my question above and finally (3) turn json-mode on by M-x json-mode in that very same buffer that's full of the example JSON, that's when I get an "Invaild JSON" error. Also, I do have the latest json-mode. I only downloaded it for the first time a few minutes before posting my comment to you above.
    – izkon
    Nov 11 '18 at 14:16
  • I can't reproduce it even with no init file. Can you post this as an issue on github? Long discussions don't belong in comments.
    – user12563
    Nov 11 '18 at 16:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.