6

I am trying to parse a string with the json.el package, though when the string is not json unexpected things happen. Is there a way in elisp to check whether or not a provided string is actually a valid json before trying to parse it with json-read-from-string?

  • 2
    The only way to know if a string is valid JSON is to try to parse it as JSON. – npostavs Jul 26 '16 at 22:15
  • @npostavs So I should try to parse it and then handle the error that's thrown if its not valid json? – lookyhooky Jul 26 '16 at 22:17
  • Be aware too of what kind of "valid" (i.e., well-formed) JSON you are interested in. In practice, most applications that use JSON allow lots of syntax that is not strict JSON syntax. – Drew Jul 27 '16 at 0:19
  • 1
    "try to parse it and then handle the error" - Yup. – npostavs Jul 27 '16 at 15:35
2

It's possible to use functionality provided by json which ships with Emacs to validate a JSON. It's a matter of trying to parse a string with it and catching any errors it might spit out.

(require 'json)

(defun my-json-string-valid-p (string)
  "Validates a JSON string."
  (condition-case nil
      (progn
        (json-read-from-string string)
        t)
    (error nil)))
1

C-x my-validate-json-or-js-expression validate the current buffer or selected region as json.

The only requirement is you need install js2-mode. (No, you don't need setup js2-mode. My code works out of box! we use js2-mode as API collection instead of major-mode)

Here is the code,

(defun my-validate-json-or-js-expression (&optional not-json-p)
  "Validate buffer or select region as JSON.
If NOT-JSON-P is not nil, validate as Javascript expression instead of JSON."
  (interactive "P")
  (let* ((json-exp (if (region-active-p) (buffer-substring-no-properties (region-beginning) (region-end))
                     (buffer-substring-no-properties (point-min) (point-max))))
         (jsbuf-offet (if not-json-p 0 (length "var a=")))
         errs
         first-err
         (first-err-pos (if (region-active-p) (region-beginning) 0)))
    (unless not-json-p
      (setq json-exp (format "var a=%s;"  json-exp)))
    (with-temp-buffer
      (insert json-exp)
      (unless (featurep 'js2-mode)
        (require 'js2-mode))
      (js2-parse)
      (setq errs (js2-errors))
      (cond
       ((not errs)
        (message "NO error found. Good job!"))
       (t
        ;; yes, first error in buffer is the last element in errs
        (setq first-err (car (last errs)))
        (setq first-err-pos (+ first-err-pos (- (cadr first-err) jsbuf-offet)))
        (message "%d error(s), first at buffer position %d: %s"
                 (length errs)
                 first-err-pos
                 (js2-get-msg (caar first-err))))))
    (if first-err (goto-char first-err-pos))))

The bonus tip is you can also C-u M-x my-validate-json-or-js-expression to validate as javascript expression. This is only useful when you don't use js2-mode for javascript file.

  • Won't this allow JS expressions that aren't valid JSON? – amitp Jul 30 '16 at 15:13
  • Yes, but in reality, the invalid json is always invalid js expression (json missing quote, bracket) – chen bin Jul 31 '16 at 3:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.