jsonlite icon indicating copy to clipboard operation
jsonlite copied to clipboard

Behavior toJSON(pretty=TRUE) differs from prettify()

Open wch opened this issue 8 years ago • 2 comments

For example:

toJSON(1:3, pretty = TRUE)
# [1, 2, 3] 

prettify(toJSON(1:3, pretty = TRUE))
# [
#     1,
#     2,
#     3
# ]

Is there way to get prettify to give output like toJSON? The reason I ask is because I want to do something like this:

x <- toJSON(list(a=1:3), pretty = TRUE)
x
# {
#   "a": [1, 2, 3]
# } 

# x is some json object that already exists by the time we get here
y <- toJSON(list(x = x), pretty=TRUE, json_verbatim=TRUE)
y
# {
#   "x": {
#   "a": [1, 2, 3]
# }
# } 


# prettify generates output that is too verbose
prettify(y, indent = 2)
# {
#   "x": {
#     "a": [
#       1,
#       2,
#       3
#     ]
#   }
# }

I would like to get output like this:

{
  "x": {
    "a": [1, 2, 3]
  }
}

Another inconsistency: the default indentation for toJSON(pretty=TRUE) is 2, but for prettify() it's 4.

wch avatar Jun 20 '17 15:06 wch

Yes this is expected. The prettify() function uses libyajl indentation which is what we used initially for pretty = TRUE. However in a later version of jsonlite with some help from yihui we added a custom indentation per R class in each asJSON method.

Therefore we can use spaces to split elements of an atomic vector, but linebreaks for lists:

jsonlite::toJSON(1:3, pretty = TRUE, auto_unbox = TRUE)
# [1, 2, 3] 
jsonlite::toJSON(as.list(1:3), pretty = TRUE, auto_unbox = TRUE)
# [
#   1,
#   2,
#   3
# ] 

Obviously we cannot see this distinction from the json itself, only if we are serializing R objects. So you would have to parse json and then reserialize it to get the R type indentations...

jeroen avatar Jun 20 '17 16:06 jeroen

I'm attempting to convert JSON to an R object, and then back to JSON, but I'm having trouble keeping the output semantically the same as the input.

Here's a function that converts from JSON to an R object, then back to JSON, and allows controlling a couple parameters in the conversion.

prettify2 <- function(x, simplifyVector = TRUE, auto_unbox = TRUE) {
  toJSON(
    fromJSON(x, simplifyVector = simplifyVector),
    auto_unbox = auto_unbox,
    pretty = TRUE
  )
}

Here's a sample JSON object. Ideally, passing it through prettify2() will result in output that looks just like the input.

xj <- '{
  "a": 1,
  "b": [1],
  "c": [1, 2],
  "d": [[1], [2]]
}'


# Output is semantically different from input
prettify2(xj, T, T)
# {
#   "a": 1,
#   "b": 1,
#   "c": [1, 2],
#   "d": [
#     [1],
#     [2]
#   ]
# } 

# Output is semantically different from input
prettify2(xj, T, F)
# {
#   "a": [1],
#   "b": [1],
#   "c": [1, 2],
#   "d": [
#     [1],
#     [2]
#   ]
# } 

# Semantically same, but too many newlines. Output is same as prettify(xj, 
# indent=2).
prettify2(xj, F, T)
# {
#   "a": 1,
#   "b": [
#     1
#   ],
#   "c": [
#     1,
#     2
#   ],
#   "d": [
#     [
#       1
#     ],
#     [
#       2
#     ]
#   ]
# } 

# Output is semantically different from input
prettify2(xj, F, F)
# {
#   "a": [1],
#   "b": [
#     [1]
#   ],
#   "c": [
#     [1],
#     [2]
#   ],
#   "d": [
#     [
#       [1]
#     ],
#     [
#       [2]
#     ]
#   ]
# } 

I don't always have control over the input JSON, so the goal is for the prettify2 function to work with any JSON. (It should prettify any JSON without semantically altering the content.)

wch avatar Jun 20 '17 17:06 wch