Skip to contents

j_patch_apply() uses JSON Patch https://jsonpatch.com to transform JSON 'data' according the rules in JSON 'patch'.

j_patch_from() computes a JSON patch describing the difference between two JSON documents.

j_patch_op() translates R arguments to the JSON representation of a patch, validating and 'unboxing' arguments as necessary.

Usage

j_patch_apply(data, patch, as = "string", ...)

j_patch_from(data_x, data_y, as = "string", ...)

j_patch_op(op, path, ...)

# Default S3 method
j_patch_op(op, path, ..., from = NULL, value = NULL)

# S3 method for class 'j_patch_op'
j_patch_op(op, ...)

# S3 method for class 'j_patch_op'
c(..., recursive = FALSE)

# S3 method for class 'j_patch_op'
print(x, ...)

Arguments

data

JSON character vector, file, URL, or an R object to be converted to JSON using jsonline::fromJSON(data, ...).

patch

JSON 'patch' as character vector, file, URL, R object, or the result of j_patch_op().

as

character(1) return type; "string" returns a JSON string, "R" returns an R object using the rules in as_r().

...

For j_patch_apply() and j_patch_diff(), arguments passed to jsonlite::toJSON when data, patch, data_x, and / or data_y is an R object. It is appropriate to add the jsonlite::toJSON() argument auto_unbox = TRUE when patch is an R object and any 'value' fields are JSON scalars; for more complicated scenarios 'value' fields should be marked with jsonlite::unbox() before being passed to j_patch_*().

For j_patch_op() the ... are additional arguments to the patch operation, e.g., path = ', value = '.

data_x

As for data.

data_y

As for data.

op

A patch operation ("add", "remove", "replace", "copy", "move", "test"), or when 'piping' an object created by j_patch_op().

path

A character(1) JSONPointer path to the location being patched.

from

A character(1) JSONPointer path to the location an object will be copied or moved from.

value

An R object to be translated into JSON and used during add, replace, or test.

recursive

Ignored.

x

An object produced by j_patch_op().

Value

j_patch_apply() returns a JSON string or R object representing 'data' patched according to 'patch'.

j_patch_from() returns a JSON string or R object representing the difference between 'data_x' and 'data_y'.

j_patch_op() returns a character vector subclass that can be used in j_patch_apply().

Details

For j_patch_apply(), 'patch' is a JSON array of objects. Each object describes how the patch is to be applied. Simple examples are available at https://jsonpatch.com, with verbs 'add', 'remove', 'replace', 'copy' and 'test'. The 'path' element of each operation is a JSON pointer; remember that JSON arrays are 0-based.

  • add – add elements to an existing document.

    {"op": "add", "path": "/biscuits/1", "value": {"name": "Ginger Nut"}}

  • remove – remove elements from a document.

    {"op": "remove", "path": "/biscuits/0"}

  • replace – replace one element with another

    {
        "op": "replace", "path": "/biscuits/0/name",
        "value": "Chocolate Digestive"
    }

  • copy – copy a path to another location.

    {"op": "copy", "path": "/best_biscuit", "from": "/biscuits/0"}

  • move – move a path to another location.

    {"op": "move", "path": "/cookies", "from": "/biscuits"}

  • test – test for the existence of a path; if the path does not exist, do not apply any of the patch.

    {"op": "test", "path": "/best_biscuit/name", "value": "Choco Leibniz"}

The examples below illustrate a patch with one (a JSON array with a single object) or several (a JSON array with several arguments) operations. j_patch_apply() fits naturally into a pipeline composed with |> to transform JSON between representations.

The j_patch_op() function takes care to ensure that op, path, and from arguments are 'unboxed' (represented as JSON scalars rather than arrays). The user must ensure that value is represented correctly by applying jsonlite::unbox() to individual elements or adding auto_unbox = TRUE to .... Examples illustrate these different scenarios.

Examples

data_file <-
    system.file(package = "rjsoncons", "extdata", "patch_data.json")

## add a biscuit
patch <- '[
    {"op": "add", "path": "/biscuits/1", "value": {"name": "Ginger Nut"}}
]'
j_patch_apply(data_file, patch, as = "R") |> str()
#> List of 1
#>  $ biscuits:List of 3
#>   ..$ :List of 1
#>   .. ..$ name: chr "Digestive"
#>   ..$ :List of 1
#>   .. ..$ name: chr "Ginger Nut"
#>   ..$ :List of 1
#>   .. ..$ name: chr "Choco Leibniz"

## add a biscuit and choose a favorite
patch <- '[
    {"op": "add", "path": "/biscuits/1", "value": {"name": "Ginger Nut"}},
    {"op": "copy", "path": "/best_biscuit", "from": "/biscuits/2"}
]'
biscuits <- j_patch_apply(data_file, patch)
as_r(biscuits) |> str()
#> List of 2
#>  $ biscuits    :List of 3
#>   ..$ :List of 1
#>   .. ..$ name: chr "Digestive"
#>   ..$ :List of 1
#>   .. ..$ name: chr "Ginger Nut"
#>   ..$ :List of 1
#>   .. ..$ name: chr "Choco Leibniz"
#>  $ best_biscuit:List of 1
#>   ..$ name: chr "Choco Leibniz"

j_patch_from(biscuits, data_file, as = "R") |> str()
#> List of 3
#>  $ :List of 3
#>   ..$ op   : chr "replace"
#>   ..$ path : chr "/biscuits/1/name"
#>   ..$ value: chr "Choco Leibniz"
#>  $ :List of 2
#>   ..$ op  : chr "remove"
#>   ..$ path: chr "/biscuits/2"
#>  $ :List of 2
#>   ..$ op  : chr "remove"
#>   ..$ path: chr "/best_biscuit"

if (requireNamespace("jsonlite", quietly = TRUE)) {
## helper for constructing patch operations from R objects
j_patch_op(
    "add", path = "/biscuits/1", value = list(name = "Ginger Nut"),
    ## 'Ginger Nut' is a JSON scalar, so auto-unbox the 'value' argument
    auto_unbox = TRUE
)
j_patch_op("remove", "/biscuits/0")
j_patch_op(
    "replace", "/biscuits/0/name",
    ## also possible to unbox arguments explicitly
    value = jsonlite::unbox("Chocolate Digestive")
)
j_patch_op("copy", "/best_biscuit", from = "/biscuits/0")
j_patch_op("move", "/cookies", from = "/biscuits")
j_patch_op(
    "test", "/best_biscuit/name", value = "Choco Leibniz",
    auto_unbox = TRUE
)

## several operations
value <- list(name = jsonlite::unbox("Ginger Nut"))
ops <- c(
    j_patch_op("add", "/biscuits/1", value = value),
    j_patch_op("copy", path = "/best_biscuit", from = "/biscuits/0")
)
ops

ops <-
    j_patch_op("add", "/biscuits/1", value = value) |>
    j_patch_op("copy", path = "/best_biscuit", from = "/biscuits/0")
ops
}
#> [
#>   {"op": "add", "path": "/biscuits/1", "value": {"name": "Ginger Nut"}}, 
#>   {"op": "copy", "path": "/best_biscuit", "from": "/biscuits/0"}
#> ]