Giuseppe Giubaldo
Giuseppe Giubaldo

Reputation: 229

json-get function in lisp

In these day i'm working to a json parse in prolog and lisp. yesterday with your help i finished the prolog project and now i need help again.

the funcion is always json-get but now in lisp.

this is the functin that i wrote:

(defun json-get (json_obj fields &optional n)
  (let ((place (assoc fields json_obj :test 'string=)))
    (if (null place)
        n
      (ns (second place) t)))

the behavior of the funtion should be the same of the prolog predicate. for example if the input is:

CL-prompt> (defparameter x (json-parse "{\"nome\" : \"Arthur\",\"cognome\" : \"Dent\"}"))
X

CL-prompt> x 
(json-obj ("nome" "Arthur") ("cognome" "Dent"))

the output should be:

CL-prompt> (json-get x "cognome")
"Dent"

insted, if the input is:

(json-get (json-parse 
                    "{\"name\" : \"Zaphod\",
                     \"heads\" : [[\"Head1\"], [\"Head2\"]]}")
         "heads" 1 0)

the output should be:

"Head2"

the function that i wrote is totally wrong?

P.S. for this project are forbidden functions like SET, SETQ, SETF e MULTIPLE-VALUE-SETQ and DO, DO*, DOTIMES, DOLIST e LOOP and DEFPARAMETER, DEFVAR e DEFCOSTANT inside a function

thanks guys

edit 1:

this is the description of this funcion,

    a json-get function that accepts a JSON object
(represented in Common Lisp, as produced by the json_parse function) and a series of
"Fields", retrieve the corresponding object. A field represented by N (with N a number
greater than or equal to 0) represents an index of a JSON array.

edit 2 : if i try to run json-get lisp answer me with:

Error: The variable PLACE is unbound.

Upvotes: 0

Views: 440

Answers (1)

Barmar
Barmar

Reputation: 781058

You need to implement this recursively. You also need to distinguish JSON arrays (which are implemented as a list of elements prefixed with json-array) and JSON objects (which are implemented as an association list.

(defun json-get (json_obj fields)
  (if (null fields) ; base case of recursion
      json_obj
    (let* ((cur-key (car fields))
           (current (cond ((and (integerp cur-key) 
                                (eq (car json_obj) 'json-array))
                           (nth (1+ cur-key) json_obj)) ; add 1 to skip over JSON-ARRAY
                          ((and (stringp cur-key) 
                                (eq (car json_obj) 'json-obj))
                           (second (assoc cur-key (cdr json_obj) :test #'string=))) ; Use CDR to skip over JSON-OBJ
                          (t (error "~S is not a JSON object or array or ~s is not appropriate key" json_obj cur-key)))))
      (json-get current (cdr fields)))))

fields has to be a list of fields, so your second example would be:

(json-get (json-parse 
                    "{\"name\" : \"Zaphod\",
                     \"heads\" : [[\"Head1\"], [\"Head2\"]]}")
          '("heads" 1 0))

and the first example should be:

(json-get x '("cognome"))

Upvotes: 0

Related Questions