将列表转换为 JSON 的最佳方法

Best way to convert a list into a JSON

我有一个看起来像这样的脚本(虽然不完全是因为我显然不能提供我的 API 密钥以及不能使它完全可复制的东西)

library(tidyverse)
library(dplyr)
library(httr)
library(civis)
library(rjson)
library(jqr)

record <- GET(
  'https://api.secure.com/v4/data',
  accept_json(),
  add_headers(Accept = 'application/json',
              Authorization = VanAPI)
)

record 然后生成一个如下所示的列表:

Response [https://api.secure.com/v4/data]
  Date: 2021-08-12 20:54
  Status: 200
  Content-Type: application/json; charset=utf-8
  Size: 873 B
{
  "items": [
    {
      "playerId": 12827,
      "name": "Player Tiers",
      "type": "Dynamic",
      "description": null,
      "points": 249,
      "areSubgroupsSticky": false,
      "status": "Active",
...

将其转换为 JSON 然后我可以将 jqr 包应用到的最佳方法是什么?

现在我在做:

test <- content(record)

产生此输出:

$items
$items[[1]]
$items[[1]]$playerId
[1] 12827

$items[[1]]$name
[1] "Player Tiers"

$items[[1]]$type
[1] "Dynamic"

$items[[1]]$description
NULL

$items[[1]]$points
[1] 249

$items[[1]]$areSubgroupsSticky
[1] FALSE

$items[[1]]$status
[1] "Active"

$items[[1]]$subgroups
NULL

$items[[1]]$markedSubgroup
NULL


$items[[2]]
$items[[2]]$playerId
[1] 15723

$items[[2]]$name
[1] "Team Tiers"

$items[[2]]$type
[1] "Dynamic"

$items[[2]]$description
NULL

$items[[2]]$points
[1] 35

$items[[2]]$areSubgroupsSticky
[1] FALSE

$items[[2]]$status
[1] "Active"

$items[[2]]$subgroups
NULL

$items[[2]]$markedSubgroup
NULL


$items[[3]]
$items[[3]]$playerId
[1] 16620

$items[[3]]$name
[1] "Coaches Tiers"

$items[[3]]$type
[1] "Dynamic"

$items[[3]]$description
NULL

$items[[3]]$points
[1] 12

$items[[3]]$areSubgroupsSticky
[1] FALSE

$items[[3]]$status
[1] "Active"

$items[[3]]$subgroups
NULL

$items[[3]]$markedSubgroup
NULL



$nextPageLink
NULL

$count
[1] 3

但后来我尝试使用 test2 <- rjson::toJSON(test) 将其转换为 JSON 但结果是:

[1] "{\"items\":[{\"playerId\":12827,\"name\":\"Player Tiers\",\"type\":\"Dynamic\",\"description\":null,\"points\":249,\"areSubgroupsSticky\":false,\"status\":\"Active\",\"subgroups\":null,\"markedSubgroup\":null},{\"playerId\":15723,\"name\":\"Team Tiers\",\"type\":\"Dynamic\",\"description\":null,\"points\":35,\"areSubgroupsSticky\":false,\"status\":\"Active\",\"subgroups\":null,\"markedSubgroup\":null},{\"playerId\":16620,\"name\":\"Coaches Tiers\",\"type\":\"Dynamic\",\"description\":null,\"points\":12,\"areSubgroupsSticky\":false,\"status\":\"Active\",\"subgroups\":null,\"markedSubgroup\":null}],\"nextPageLink\":null,\"count\":3}"

有没有更好的方法来获得简单、干净的 JSON 输出?

阅读?content,你会看到

      as: desired type of output: 'raw', 'text' or 'parsed'. 'content'
          attempts to automatically figure out which one is most
          appropriate, based on the content-type.

继续他们的例子,

library(httr)
r <- POST("http://httpbin.org/post", body = list(a = 1, b = 2))
r
# Response [http://httpbin.org/post]
#   Date: 2021-08-12 22:15
#   Status: 200
#   Content-Type: application/json
#   Size: 586 B
# {
#   "args": {}, 
#   "data": "", 
#   "files": {}, 
#   "form": {
#     "a": "1", 
#     "b": "2"
#   }, 
#   "headers": {
#     "Accept": "application/json, text/xml, application/xml, */*", 
# ...

content 的“正常”使用为我们提供了我们期望的命名列表:

str(content(r))
# List of 8
#  $ args   : Named list()
#  $ data   : chr ""
#  $ files  : Named list()
#  $ form   :List of 2
#   ..$ a: chr "1"
#   ..$ b: chr "2"
#  $ headers:List of 7
#   ..$ Accept         : chr "application/json, text/xml, application/xml, */*"
#   ..$ Accept-Encoding: chr "deflate, gzip"
#   ..$ Content-Length : chr "228"
#   ..$ Content-Type   : chr "multipart/form-data; boundary=------------------------99386898172ff715"
#   ..$ Host           : chr "httpbin.org"
#   ..$ User-Agent     : chr "libcurl/7.64.1 r-curl/4.3 httr/1.4.1"
#   ..$ X-Amzn-Trace-Id: chr "Root=1-61159d7a-55ef1d2f553f80fa4773ae03"
#  $ json   : NULL
#  $ origin : chr "172.254.236.28"
#  $ url    : chr "http://httpbin.org/post"

我们可以使用 as="text" 获取原始 json 文本:

content(r, as="text")
# No encoding supplied: defaulting to UTF-8.
# [1] "{\n  \"args\": {}, \n  \"data\": \"\", \n  \"files\": {}, \n  \"form\": {\n    \"a\": \"1\", \n    \"b\": \"2\"\n  }, \n  \"headers\": {\n    \"Accept\": \"application/json, text/xml, application/xml, */*\", \n    \"Accept-Encoding\": \"deflate, gzip\", \n    \"Content-Length\": \"228\", \n    \"Content-Type\": \"multipart/form-data; boundary=------------------------99386898172ff715\", \n    \"Host\": \"httpbin.org\", \n    \"User-Agent\": \"libcurl/7.64.1 r-curl/4.3 httr/1.4.1\", \n    \"X-Amzn-Trace-Id\": \"Root=1-61159d7a-55ef1d2f553f80fa4773ae03\"\n  }, \n  \"json\": null, \n  \"origin\": \"172.254.236.28\", \n  \"url\": \"http://httpbin.org/post\"\n}\n"

虽然这并不漂亮,但这正是远程服务器返回的内容:从 http://httpbin.org/post 端点 returns:

您应该能够使用任何 json 处理器处理此 json,包括 jsonlite::fromJSON(已确认)并且可能 rjsonjqr(甚至在将其保存到文本文件后在命令行上 jq

以下是@r2evans 给出的答案的补充。

尽管 content(r) 似乎是一个 JSON 编码的字符串,jqr 命令将其识别为 JSON 文本,因此(使用 jqr 时)不需要运行 通过 jq 的 fromjson 过滤器。

例如:

> library(httr)
> library(jqr)
> r <- GET("https://raw.githubusercontent.com/postmanlabs/httpbin/master/app.json")
> jq(content(r))
{
    "name": "httpbin",
    "description": "HTTP Request & Response Service, written in Python + Flask.",
    "repository": "https://github.com/requests/httpbin",
    "website": "https://httpbin.org",
    "logo": "https://s3.amazonaws.com/f.cl.ly/items/333Y191Z2C0G2J3m3Y0b/httpbin.svg",
    "keywords": [
        "http",
        "rest",
        "API",
        "testing",
        "integration",
        "python",
        "flask"
    ],
    "addons": "sentry"
}

> jq(content(r), ".name")
"httpbin"