yitzchak / shasht

Common Lisp JSON reading and writing for the Kzinti.
MIT License
46 stars 3 forks source link

Option to convert keys to keywords #6

Open sebasmonia opened 2 years ago

sebasmonia commented 2 years ago

This is simple to do manually after de-serializing, but having the option built-in it would be nice. Converting a JSON string to an alist, sometimes it is desirable to treat JSON keys as keywords.

An example:

CL-USER> (defvar *simple-test* '((:a . 1) (:b . 2)))
*SIMPLE-TEST*
CL-USER> (with-input-from-string (s (shasht:write-json* *simple-test* :alist-as-object t :stream nil))
           (shasht:read-json* :stream s :object-format :alist))
(("A" . 1) ("B" . 2))
CL-USER>

Given the code above, a way to get back ((:A . 1) (:B . 2)) after calling read-json can be convenient. I don't think it should be the default, and it could even work for hash-table keys too, in the default object format. (for less :test #'equal arguments :smile:)

yitzchak commented 2 years ago

I am not saying I am completely opposed to this, but some have pointed out that this is security risk.

https://sabracrolleton.github.io/json-review#security

In general using hash tables is the best fit for JSON. On the other hand, do you have a use case? I can think about it if you do.

sebasmonia commented 2 years ago

I don't have a particularly strong use case, I just happened to have an alist and was using keywords as keys for convenience.
I dumped the data to a file and noticed that reading it back I had to convert the string keys to keywords again.
And, in my case it was a couple hundred entries, so it wasn't a big deal to loop and create a new alist with keyword :) Considering the security implications, it is probably better not to do this.

yitzchak commented 2 years ago

In the case of plists I think the justification is a bit stronger. There is a dynamic variable *symbol-name-function* that is used to control what function to use get the name of the symbol. This is only done on the write-json side. I'll look into providing a generic way to do this on both the write and the read side and probably leave it up to the user to override it if they wish.

Mr-Dispatch commented 1 year ago

I've just added a special var & read-json* keyword parameter for make-hash-table :test designator. With EQUALP, I can use keywords in code, let my API translate it into strings, and have the hash-table not care about it being uppercase. The service I'm talking to is case-insensitive, so it is a win all-around.

Interested in PR ?

yitzchak commented 1 year ago

@Mr-Dispatch you don't need to ask permission to submit a PR. Just do it. I'll review it without preconditions.

Mr-Dispatch commented 1 year ago

I was more like asking whether it would even be considered a feature (I haven't even cloned, I just edited on a whim, copied to my .local-projects, ql:uninstalled ultralisp original, restarted, enjoyed).

PR would be a "few more keystrokes" ;-)