在Common Lisp

时间:2018-05-31 10:04:39

标签: json common-lisp

我一直在使用spotify API,以便熟悉常见的Lisp。这种语言与我习以为常的大不相同,我担心我可能会对如何解析对象和列表缺乏一些了解。

当我按照标题查看spotify API查找歌曲时。它返回了很多我使用cl-json解码方法访问的json。然而,为了访问任何字段,我发现自己做了很长的嵌套汽车cdr组合。 cl-json不返回listp或lista,而是返回嵌套cons的巨大列表。这似乎是一个解析的噩梦。我附上下面的代码作为例子。所以我想问的是,我错过了什么?这个代码在LISP中看起来像繁琐和混乱的方式,并且我假设有一种很好的方法将所有JSON映射到某种类型的对象或分层树?这将使查询更容易。

(ql:quickload '(:cl-json :drakma))
(defvar *auth-token*)   
(defvar *results*)
(setq *url* "https://api.spotify.com/v1/search")
(push (cons "application" "json") drakma:*text-content-types*)
(setf drakma:*header-stream* *standard-output*)

(defun search-spotify (&optional (search-param "blue moon")  (search-type "track") (limit 5))
  "Perform a search on the API for track, artist, or album information"
  (defvar complete-url "")
  (defvar url nil)
  (defvar params nil)
  (setq url "https://api.spotify.com/v1/search")
  (setq params (format nil "?q=~a&type=~a&limit=~a" (replace-all search-param " " "+") (replace-all search-type " " "+") limit))
  (setq complete-url (format nil "~a~a" url params))
  (print complete-url)
  (setq *results* (cl-json:decode-json-from-string
                   (drakma:http-request complete-url
                                        :method :get
                                        :additional-headers `(("Authorization" . ,(format nil "Bearer ~a" (cdar *auth-token*))))
                                        ))))

(defun print-spotify-artist ()
  (loop for result in (cdr (caddar *results*))
        do (format t "Artist Name: ~a Spotify ID: ~a ~%" (cdadr (cddadr (caddar result))) (cdar (cdaadr (caddar result))))))

运行上面的代码并调用print-spotify-artist函数将打印如下列表:

  

艺术家姓名:Eve 6 Spotify ID:   https://open.spotify.com/artist/4Eqd24yS5YcxI8b6Xfuwr8艺术家姓名:   Bill Murray Spotify ID:   https://open.spotify.com/artist/3wkZ8WTrs7WcfE13voUCK1艺术家姓名:   各位艺术家Spotify ID:   https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of艺术家姓名:   Pat Martino Spotify ID:   https://open.spotify.com/artist/4DlMMgnldzX6OkCskmeGKz艺术家姓名:   杰斯& Zeb Spotify ID:   https://open.spotify.com/artist/1oAndP8vmGtTlB6mbpieJs

示例JSON返回,您为每首歌曲返回此内容,对于此示例数据,我将最大结果设置为1.请注意,它是严重嵌套的。以下是从cl-json的decode json函数返回的内容。

    ((:TRACKS
  (:HREF
   . "https://api.spotify.com/v1/search?query=open%2Broad%2Bsong&type=track&offset=0&limit=1")
  (:ITEMS
   ((:ALBUM (:ALBUM--TYPE . "album")
     (:ARTISTS
      ((:EXTERNAL--URLS
        (:SPOTIFY . "https://open.spotify.com/artist/4Eqd24yS5YcxI8b6Xfuwr8"))
       (:HREF . "https://api.spotify.com/v1/artists/4Eqd24yS5YcxI8b6Xfuwr8")
       (:ID . "4Eqd24yS5YcxI8b6Xfuwr8") (:NAME . "Eve 6") (:TYPE . "artist")
       (:URI . "spotify:artist:4Eqd24yS5YcxI8b6Xfuwr8")))
     (:AVAILABLE--MARKETS "AD" "AR" "AT" "AU" "BE" "BG" "BO" "BR" "CA" "CH"
      "CL" "CO" "CR" "CY" "CZ" "DE" "DK" "DO" "EC" "EE" "ES" "FI" "FR" "GB"
      "GR" "GT" "HK" "HN" "HU" "ID" "IE" "IL" "IS" "IT" "JP" "LI" "LT" "LU"
      "LV" "MC" "MT" "MY" "NI" "NL" "NO" "NZ" "PA" "PE" "PH" "PL" "PT" "PY"
      "RO" "SE" "SG" "SK" "SV" "TH" "TR" "TW" "US" "UY" "VN" "ZA")
     (:EXTERNAL--URLS
      (:SPOTIFY . "https://open.spotify.com/album/1qJOmC60ez9RNWPg4ELMBW"))
     (:HREF . "https://api.spotify.com/v1/albums/1qJOmC60ez9RNWPg4ELMBW")
     (:ID . "1qJOmC60ez9RNWPg4ELMBW")
     (:IMAGES
      ((:HEIGHT . 639)
       (:URL
        . "https://i.scdn.co/image/3f7891ffa993954dd72ed50245280b15f5db5844")
       (:WIDTH . 621))
      ((:HEIGHT . 300)
       (:URL
        . "https://i.scdn.co/image/16f1a6277b827fd97cb450c5dc246d29c2ed1d52")
       (:WIDTH . 291))
      ((:HEIGHT . 64)
       (:URL
        . "https://i.scdn.co/image/935aca4d861213415fc64f780b0e9e5a0e8d865c")
       (:WIDTH . 62)))
     (:NAME . "Eve 6") (:RELEASE--DATE . "1998")
     (:RELEASE--DATE--PRECISION . "year") (:TYPE . "album")
     (:URI . "spotify:album:1qJOmC60ez9RNWPg4ELMBW"))
    (:ARTISTS
     ((:EXTERNAL--URLS
       (:SPOTIFY . "https://open.spotify.com/artist/4Eqd24yS5YcxI8b6Xfuwr8"))
      (:HREF . "https://api.spotify.com/v1/artists/4Eqd24yS5YcxI8b6Xfuwr8")
      (:ID . "4Eqd24yS5YcxI8b6Xfuwr8") (:NAME . "Eve 6") (:TYPE . "artist")
      (:URI . "spotify:artist:4Eqd24yS5YcxI8b6Xfuwr8")))
    (:AVAILABLE--MARKETS "AD" "AR" "AT" "AU" "BE" "BG" "BO" "BR" "CA" "CH" "CL"
     "CO" "CR" "CY" "CZ" "DE" "DK" "DO" "EC" "EE" "ES" "FI" "FR" "GB" "GR" "GT"
     "HK" "HN" "HU" "ID" "IE" "IL" "IS" "IT" "JP" "LI" "LT" "LU" "LV" "MC" "MT"
     "MY" "NI" "NL" "NO" "NZ" "PA" "PE" "PH" "PL" "PT" "PY" "RO" "SE" "SG" "SK"
     "SV" "TH" "TR" "TW" "US" "UY" "VN" "ZA")
    (:DISC--NUMBER . 1) (:DURATION--MS . 194866) (:EXPLICIT)
    (:EXTERNAL--IDS (:ISRC . "USRC19806851"))
    (:EXTERNAL--URLS
     (:SPOTIFY . "https://open.spotify.com/track/7kAKO1EYHt2MVlombUuoLN"))
    (:HREF . "https://api.spotify.com/v1/tracks/7kAKO1EYHt2MVlombUuoLN")
    (:ID . "7kAKO1EYHt2MVlombUuoLN") (:IS--LOCAL) (:NAME . "Open Road Song")
    (:POPULARITY . 44)
    (:PREVIEW--URL
     . "https://p.scdn.co/mp3-preview/b793285aeeb4a1176b93dc739ffb361c6aabf4e5?cid=b067abcbc67f4ceba0d61e414926c9f5")
    (:TRACK--NUMBER . 5) (:TYPE . "track")
    (:URI . "spotify:track:7kAKO1EYHt2MVlombUuoLN")))
  (:LIMIT . 1)
  (:NEXT
   . "https://api.spotify.com/v1/search?query=open%2Broad%2Bsong&type=track&offset=1&limit=1")
  (:OFFSET . 0) (:PREVIOUS) (:TOTAL . 43))) 

1 个答案:

答案 0 :(得分:1)

Access library可能有所帮助,它允许访问嵌套数据结构。

(defparameter my-plist (list :foo "foo" :bar "bar"))

;; bar is a plist
(defclass obj-test ()
  ((foo :accessor foo :initarg :foo :initform :foo)
   (bar :accessor bar :initarg :bar :initform (copy-list MY-PLIST))))

(defvar my-obj ((make-instance 'obj-test))

(accesses MY-OBJ 'bar 'foo) ;; => "foo"

如果您愿意,可以使用虚线路径。

Access是经过测试的,它是Djula模板引擎的核心,是Quicklisp上下载量最大的库之一。

Access还允许跨数据结构的一致访问。

更深入的概述:https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/

相关问题