tojson: A simple JSON serializer

View source: R/json.R

tojsonR Documentation

A simple JSON serializer

Description

A JSON serializer that only works on a limited types of R data (NULL, lists, arrays, logical/character/numeric/date/time vectors). Other types of data will be coerced to character. A character string wrapped in js() is treated as raw JavaScript, so will not be quoted. The function json_vector() converts an atomic R vector to JSON.

Usage

tojson(
  x,
  dict = getOption("xfun.tojson.dict", 0),
  pretty = getOption("xfun.tojson.pretty", TRUE),
  pack = getOption("xfun.tojson.pack", Inf),
  mode = getOption("xfun.tojson.mode", "js")
)

json_unpack

json_reviver

js(x)

json_vector(x, to_array = FALSE, quote = TRUE, sep = ", ", mode = "js")

Arguments

x

An R object.

dict

A number controlling whether to dictionary-encode atomic vectors (and data-frame columns) to shrink the output when values repeat. Defaults to the global option xfun.tojson.dict (and to 0 when that is unset), so a package that embeds tojson() output deep inside another function can turn encoding on without the call being reachable, e.g. options(xfun.tojson.dict = 0.5). 0 serializes normally. A number in ⁠(0, 1]⁠ acts as a cardinality threshold: a vector is encoded when its number of unique values is at most dict times its length, and only when the encoding is actually shorter than the plain form (so near-unique vectors are left alone); 1 considers every vector. An encoded vector becomes a runnable JavaScript expression ⁠[codes].map(i => [u][i])⁠ (0-based codes indexing the unique values u), which is not strict JSON but meant to be evaluated as JavaScript (e.g. embedded in a ⁠<script>⁠). With mode = "json" the encoded vector instead becomes the valid-JSON object ⁠{"<tag>u": [uniques], "<tag>c": [codes]}⁠ that json_reviver expands back to the vector.

pretty

Whether to pretty-print the output with line breaks, indentation, and a space after each array/object separator. Defaults to the global option xfun.tojson.pretty (and to TRUE when that is unset), so an embedding package can turn pretty-printing off without reaching the call, e.g. options(xfun.tojson.pretty = FALSE). FALSE produces a compact, single-line result (no line breaks or indentation, and ⁠,⁠ instead of ⁠, ⁠ between array elements), which can be substantially smaller for large data.

pack

Whether to pack long integer vectors as base64 (little-endian bytes, 1/2/4 bytes per value chosen by range) to shrink the output and speed up parsing. Defaults to the global option xfun.tojson.pack (and to Inf when that is unset). A number giving the minimum vector length to pack (Inf disables packing). Vectors containing NA are not packed, and packing is used only when it shortens the output. The packed representation depends on mode (see below).

mode

Whether to emit standard JSON or JavaScript, one of "js" (default) or "json"; defaults to the global option xfun.tojson.mode. This is the master switch over every construct that is not strict JSON: dates, infinities (see above), and dict- and pack-encoded vectors.

With mode = "json" the whole result is valid JSON that JSON.parse() accepts. A packed vector is {"<tag>": "<base64>"}, where the tag is a fixed prefix (a leading control char, unlikely to collide with a real key) plus u8, u16, u32 for unsigned or i8, i16, i32 for signed integers. A consumer turns packed (and dict) values back into typed arrays with the JavaScript json_unpack (defines unpack(o), decode one packed object on demand) or json_reviver (also defines reviver, for JSON.parse(text, reviver)). Prefer lazy unpack() over reviver for large payloads: a reviver fires on every parsed value, so attaching it to a document that still holds large plain arrays can make JSON.parse() an order of magnitude slower (vs. no reviver); on a mostly-packed document the two cost about the same.

With mode = "js" the result is instead a self-contained JavaScript expression: each packed vector becomes an unpack({...}) call (and a dict vector ⁠Array.from(unpack({...}), i => u[i])⁠), with unpack() defined once in a wrapping ⁠(() => {...})()⁠. The whole result is a single expression to be evaluated (not JSON.parsed), so the consumer needs no reviver and the tags appear only as call arguments, never as standalone data. Use this when the output is embedded as a JS value; use "json" when it must stay valid JSON.

to_array

Whether to convert a vector to a JSON array (use ⁠[]⁠).

quote

Whether to double quote the elements.

sep

The string separating consecutive array elements (', ' by default; use ',' for compact output).

Format

json_unpack and json_reviver are character strings of JavaScript source.

Details

Both NULL and NA are converted to null. Named lists are converted to objects of the form ⁠{key1: value1, key2: value2, ...}⁠. Unnamed lists are converted to arrays of the form ⁠[[value1], [value2], ...]⁠. The same rules apply to data frames since technically they are also lists. However, please note that unnamed data frames (i.e., without column names) will be converted to an array with each row as an array element, whereas named data frames will have each column as an individual element. For matrices, the JSON array will have each row as an individual element, and names are discarded.

Dates and times are coerced to character using UTC as the timezone. By default (mode = "js") they are represented via the JavaScript expression ⁠new Date(value)⁠ (not standard JSON but practically more useful), and Inf/-Inf as the JavaScript literals Infinity/-Infinity; with mode = "json" they become a plain quoted string and null, respectively, so the output is standard JSON (see the mode argument).

Value

A character string.

See Also

The jsonlite package provides a full JSON serializer.

Examples

library(xfun)
tojson(NULL); tojson(1:10); tojson(TRUE); tojson(FALSE)
tojson(list(a = 1, b = list(c = 1:3, d = "abc")))
tojson(list(c("a", "b"), 1:5, TRUE, Sys.Date() + 1:3))
tojson(head(iris))  # each column is in an element
tojson(unname(head(iris)))  # each row is in an element
tojson(matrix(1:12, 3))

# dictionary-encode repeated values
tojson(rep(c("b", "a", NA), 3), dict = 1)

# literal JS code
tojson(list(a = 1:5, b = js("function() {return true;}")))

# pure static JSON: dates become strings and Inf becomes null
tojson(list(d = as.Date("2024-01-15"), x = c(1, Inf)), mode = "json")

xfun documentation built on Oct. 16, 2026, 9:06 a.m.