8000 GitHub - emacsmirror/jsonp: Resolve JSON pointers in ELisp objects
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Resolve JSON pointers in ELisp objects

License

Notifications You must be signed in to change notification settings

emacsmirror/jsonp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jsonp.el

This library provides functions to resolve JSON pointers (as defined in RFC6901) within parsed JSON objects, also supporting remote resolution (fetching JSON from a URI).

JSON pointers can be resolved whether your JSON is parsed as an alist, plist or a hash table.

It also includes functions to replace JSON references ($ref) as used in JSON schema and OpenAPI.

Basic Usage

First add the library to your load path.

(require 'jsonp)

;; Resolve a JSON pointer within a parsed JSON object
(let ((json-object (json-read-from-string "{\"a\": {\"b\": 1}}"))
      (pointer "/a/b"))
  (jsonp-resolve json-object pointer)) ;; Returns 1

;; Resolve a remote JSON pointer
;; jsonp-remote configures how to fetch and parse the remote JSON
(jsonp-resolve-remote (jsonp-remote) "https://example.com/data.json#/a/b")

;; Resolve a JSON pointer without signalling errors
(jsonp-resolve-safe json-object "/non/existent/path") ;; Returns nil

;; Replace JSON references
;; THIS MODIFIES THE ARGUMENT OBJECT!
(let ((json-object (json-read-from-string "{\"a\": {\"$ref\": \"#/b\"}, \"b\": 1}")))
  (jsonp-replace-refs json-object)) ;; Returns '((a . 1) (b . 1))

Dependencies

  • Emacs 28.1 or later

Resolving Remote JSON Pointers

When resolving remote JSON pointers, you can customize the JSON parser and the URL fetcher using an instance of the jsonp-remote class.

To use the default settings, just call jsonp-remote with no arguments

;; Resolve a remote JSON pointer with default settings
(jsonp-resolve-remote (jsonp-remote) "https://example.com/data.json#/a/b")

Note that the default URL fetcher is url-retrieve-synchronously, which blocks.

Responses are cached, so in most cases performance should be adequate.

Custom JSON Parser

The JSON parser function should accept a single string value and return an object.

;; custom JSON parser
(let* ((json-as-plist (lambda (string) (json-parse-string string :object-type 'plist)))
       (my-remote (jsonp-remote :json-parser json-as-plist)))
  (jsonp-resolve-remote my-remote "https://example.com/data.json#/a/b")) ;; (:foo (:bar 1))

Custom URL fetcher

The URL fetcher should accept a URL string and return a JSON string. Note that the JSON parser is always applied, the default is json-parse-string. For example, using plz.el to fetch

(require 'plz)
;; custom URL fetcher
(let* ((plz-get-string (lambda (url) (plz 'get url)))
       (my-remote (json-remote :url-fetcher plz-get-string)))
  (jsonp-resolve-remote my-remote "https://example.com/data.json#/a/b"))

;; Note that the default JSON parser expects a string, so this will not work
(let* ((plz-get-string (lambda (url) (plz 'get url :as #'json-read))) ;; using the plz JSON parser
       (my-remote (json-remote :url-fetcher plz-get-string)))
  (jsonp-resolve-remote my-remote "https://example.com/data.json#/a/b")) ;; ERROR

The cache operates with custom URL fetchers too.

Whitelisting Domains

You can use a whitelist to restrict URL fetching to a single domain:

(let* ((my-domains '("https://foo.com/.*" "https://.*.foo.com"))
       (my-remote (jsonp-remote :whitelist my-domains)))
  (jsonp-resolve-remote my-remote "https://example.com/data.json#/a/b") ;; ERROR
  (jsonp-resolve-remote my-remote "https://bar.foo.com/data.json#/a")) ;; OK

The whitelist is checked before calling the URL fetcher, so this will work even with a custom URL parser.

Resolving with $ref

If you need to resolve pointers within $ref objects, you can use the jsonp-nested-elt function. It is similar to map-nested-elt in that it takes a list of keys, but it will resolve any $ref properties as JSON pointers, and it will signal an error if the keys don’t resolve.

For example, given this JSON

{
  "$defs": {
    "nonEmptyString": {
      "type": "string",
      "minLength": 1
    }
  },
  "type": "object",
  "properties": {
    "name": {
      "type": "object",
      "properties": {
        "firstName": { "$ref": "#/$defs/nonEmptyString" },
        "lastName": { "$ref": "#/defs/nonEmptyString" }
      }
    }
  }
}

resolve #/properties/name/properties/firstName/type

(jsonp-nested-elt the-json '(properties name properties firstName type)) ;; "string"

Note that the list of keys can include strings, symbols or numbers. Strings and symbols are automatically converted, so the following also works

(jsonp-nested-elt the-json '("properties" "name" "properties" "firstName" "type")) ;; "string"

Contributing

Contributions are welcome!

Releases

No releases published

Packages

No packages published
0