Как получить yason: encode-alist для возврата закодированной строки вместо отправки ее в поток? - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь закодировать строку JSON из alist с помощью YASON. Проблема в том, что возвращаемое значение, которое я получаю, это исходный список, который я его кормил. Он печатает строку JSON, и согласно документации он переходит к *STANDARD-OUTPUT*.

Простой пример сеанса:

(ql:quickload :yason)
To load "yason":
  Load 1 ASDF system:
    yason
; Loading "yason"

(:YASON)
* (defparameter starving-json-eater (yason:encode-alist '(("foo" . "bar") ("baz" . "qux"))))
{"foo":"bar","baz":"qux"}
STARVING-JSON-EATER
* starving-json-eater

(("foo" . "bar") ("baz" . "qux"))

Я пытался передать 'starving-json-eater в параметр stream, но получаю ошибку:

* (setf starving-json-eater (yason:encode-alist '(("foo" . "bar") ("baz" . "qux")) 'starving-json-eater))

debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {1001E06783}>:
  There is no applicable method for the generic function
    #<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-WRITE-CHAR (1)>
  when called with arguments
    (STARVING-JSON-EATER #\{).

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY] Retry calling the generic function.
  1: [ABORT] Exit debugger, returning to top level.

((:METHOD NO-APPLICABLE-METHOD (T)) #<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-WRITE-CHAR (1)> STARVING-JSON-EATER #\{) [fast-method]

Как мне получить {"foo":"bar","baz":"qux"} в starving-json-eater?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

Вы можете использовать WITH-OUTPUT-TO-STRING, чтобы временно связать переменную с открытым потоком, который записывает в строку. Вы можете даже связать специальную переменную *standard-output*, чтобы изменить динамический контекст вашего кода, не предоставляя явно другой аргумент потока (например, когда вы перенаправляете потоки с процессами).

(with-output-to-string (*standard-output*)
  (yason:encode-alist '(("a" . "b"))))

Обратите внимание, что привязка *standard-output* означает, что все, что записывает в *standard-output*, в конечном итоге будет записано в строку в течение with-output-to-string. В приведенном выше случае область действия достаточно ограничена, чтобы избежать неожиданного захвата вывода из вложенного кода. Вы также можете использовать лексическую переменную для точного управления тем, кто пишет в строку:

(with-output-to-string (json)
  (yason:encode-alist '(("a" . "b")) json))
0 голосов
/ 27 августа 2018

Хитрость заключается в том, чтобы создать поток вывода одноразовой строки, чтобы перехватить значение, а затем получить его позже:

* (ql:quickload :yason)
To load "yason":
  Load 1 ASDF system:
    yason
; Loading "yason"

(:YASON)
* (defparameter sated-json-eater (make-string-output-stream))

SATED-JSON-EATER
* (yason:encode-alist '(("foo" . "bar") ("baz" . "qux")) sated-json-eater)

(("foo" . "bar") ("baz" . "qux"))
* (defparameter json-string (get-output-stream-string sated-json-eater))

JSON-STRING
* json-string

"{\"foo\":\"bar\",\"baz\":\"qux\"}"

Это можно скрыть в функции:

(defun json-string-encode-alist (alist-to-encode)
  (let ((stream (make-string-output-stream)))
    (yason:encode-alist alist-to-encode stream)
    (get-output-stream-string stream)))
...