travis_status codecov docs_badge CRAN_badge

Reading JSON into R usually leaves you with some deeply-nested list objects which are a pain to munge and navigate — applying path expressions is one way to make this easier. rjsonpath implements JSONPath, a selector / querying language for JSON, similar to XPath for XML.

Install

Install from github with:

devtools::install_github("blmoore/rjsonpath")

Usage

As an example, take this simple JSON:

{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}

Via read_json this can be read into R as:

json
#> $menu
#> $menu$id
#> [1] "file"
#> 
#> $menu$value
#> [1] "File"
#> 
#> $menu$popup
#> $menu$popup$menuitem
#> $menu$popup$menuitem[[1]]
#>            value          onclick 
#>            "New" "CreateNewDoc()" 
#> 
#> $menu$popup$menuitem[[2]]
#>       value     onclick 
#>      "Open" "OpenDoc()" 
#> 
#> $menu$popup$menuitem[[3]]
#>        value      onclick 
#>      "Close" "CloseDoc()"

Pretty horrible right? To gather all the onclick methods into a vector with base R you might write:

sapply(json$menu$popup$menuitem, `[[`, "onclick")
#> [1] "CreateNewDoc()" "OpenDoc()"      "CloseDoc()"

Using rjsonpath this could instead be:

json_path(json, "$.menu.popup.menuitem[*].onclick")
#> [1] "CreateNewDoc()" "OpenDoc()"      "CloseDoc()"

Or even just:

json_path(json, "$..onclick")
#> NULL

For more more complex examples, see below.

Advanced expressions

For more complex JSON documents it’s common to combine filters, array slices and recursive descent. The following examples use a simple “store” object similar to the one in the original JSONPath specification:

Filter expressions

Select only books cheaper than 10:

json_path(store, "$.store.book[?(@.price < 10)].title")
#> NULL

Select books that have an isbn field:

json_path(store, "$.store.book[?(@.isbn)].title")
#> [1] "Moby Dick"             "The Lord of the Rings"

Recursive descent

Get all prices anywhere under store:

json_path(store, "$.store..price")
#> [1]  8.95 12.99  8.99 22.99 19.95

Get all authors anywhere in the document:

json_path(store, "$..author")
#> [1] "Nigel Rees"       "Evelyn Waugh"     "Herman Melville"  "J. R. R. Tolkien"

Array slices and unions

Select a slice of books (second and third) and return their titles:

json_path(store, "$.store.book[1:3].title")
#> [1] "Sword of Honour" "Moby Dick"

Select a non‑contiguous subset of books by index:

json_path(store, "$.store.book[0,3].title")
#> [1] "Sayings of the Century" "The Lord of the Rings"