Giuseppe Giubaldo
Giuseppe Giubaldo

Reputation: 229

write json object in lisp

Good morning i need help to write this function in lisp. this is the description.

The json-write function writes the JSON object to the filename file in JSON syntax. If filename does not exist, it is created and if it exists it is overwritten. Of course it is expected that

    CL-PROMPT> (json-load (json-write '(json-obj # | stuff | #) "foo.json"))
    (json-obj # | stuff | #)

and this is my function but it isn't correct

 (defun json-write (json filename)
  (with-open-file (out filename
                       :direction :output
                       :if-exists :overwrite
                       :if-does-not-exist :create)
    (pprint (json out))))

thanks

Edit 1:

i try to write var json (that is a json object) into filename.

but pprint doesn't write anything to filename

Edit 2:

(defun json-write (json filename)
  (with-open-file (out filename
                       :direction :output
                       :if-exists :supersede
                       :if-does-not-exist :create)
    (cond
     ((equal (first json) ‘json-array) (write-arr json))
     ((equal (first json) ‘json-obj) (write-obj json)))))

so i try this now

if json is json-array lisp call write-arr json if json is json-obj call write-obj

so my idea is that write-arr trasform

(json-array 1 2 3) in `"[1, 2, 3]"` to make it parsable 

and write-obj trasform

(json-obj ("nome" "Arthur") ("cognome" "Dent"))

in

"{\"nome\" : \"Arthur\",
\"cognome\" : \"Dent\"}"

and then write everythings into filename with format stream.

how can i format (json-array 1 2 3) in "[1, 2, 3]".

with format function? and then calling recursively even this function?

thank you

Upvotes: 1

Views: 823

Answers (1)

Dan Robertson
Dan Robertson

Reputation: 4360

When you write (pprint (json out)) you are trying to call a global function called json. I think you mean (pprint json out).

Now here is roughly how to write a simple json printer:

(defun write-json (object stream)
  (etypecase object
    (number (format stream “~a” object))
    (string (print object stream))
    (null (format stream “null”))
    (cons
      (ecase (car object)
        (json-array
          (write-char #\[ stream)
          (loop for (x . r) on (cdr object)
            do (write-json x stream)
               (when r (write-char #\, stream)))
          (write-char #\] stream))))))

There are plenty of gaps to fill in. And note that this will print strings wrong if they contain new lines. And you probably want to do something less stupid for printing numbers.

Here is how I would implement a json pretty printer with CLOS:

(defvar *json-pretty* nil)
(defvar *json-indent-level* 0)
(defvar *json-indent-spaces* 2)
(defun json-fresh-line (stream)
  (if *json-pretty*
    (progn
      (fresh-line stream)
      (loop repeat (* *json-indent-level* *json-indent-spaces*)
        do (write-char #\Space stream)))
    (write-char #\Space stream))
(defgeneric write-json (object stream))
(defgeneric write-json-collection (type data stream))
(defmethod write-json ((object cons) stream)
  (write-json-collection (car object) (cdr object) stream))
(defmethod write-json-collection ((tag (eql json-array)) data stream)
  ...)

There are plenty of methods left to write.

Upvotes: 1

Related Questions