- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello all,
I think I have come up with an acceptable parser for JSON -> Lists. Hopefully.
But let's be honest, it'll probably break eventually haha..
With my preliminary testing on the 3 attached files (i have tested more, only attached 3) it appears to be working normally and as-expected. But I'm hoping I can get feedback / improvements!
This initial version is actually entirely in 'vanilla' Autolisp (no VisualLisp), so any future releases I will just dictate with an identifier at the top (al = AutoLisp / vl = VisualLisp).
Ideally, the final function should NOT include a 'read' function as this one currently does. But for now, this is a step in the right direction I believe.
It's definitely pretty slow at the moment, but it can handle its own.
The main reason I looked into this was after realizing that the (read) function cannot handle 'symbols' over ~2000 characters (so, one long continuous string [as found in the attached 'Example JSON Google API'] will cause my original (much easier) function to fail:
(defun JSON->LIST (json / tmp dbl nwl) ;json - string, as json data ;returns - list or nil, list of data converted from json (if (eq 'STR (type json)) (read (vl-string-translate "[]{}:," "()() " json)) nil) );defun
Here's the function.. Let me know what you think:
(defun ParseJSON->List (json / cnt len prevChar ch endPos tmp ret) ;Coded by Denon Deterding (Version al:1.0 - 20200221) ;json - string, of json data to convert ;returns - list, of converted json ;helper function(s) (defun EndOfQuote (str pos / ch cnt prevChar found) (setq cnt 0 prevChar "" found nil) (while (not found) (setq ch (substr str (+ pos (setq cnt (1+ cnt))) 1)) (if (and (eq "\"" ch) (not (eq "\\" prevChar))) (setq found t pos (+ cnt pos))) (setq prevChar ch) );while pos );defun (defun EndOfBracket (str pos openChar / ch cnt prevChar found inStr closeChar) (setq cnt -1 prevChar "" found nil inStr nil closeChar (if (eq "{" openChar) "}" "]")) (setq openCnt 0 closeCnt 0) (while (not found) (setq ch (substr str (+ pos (setq cnt (1+ cnt))) 1)) (if (and (eq "\"" ch) (not (eq "\\" prevChar))) (setq inStr (not inStr))) (cond ((and (not inStr) (eq openChar ch)) (setq openCnt (1+ openCnt))) ((and (not inStr) (eq closeChar ch)) (setq closeCnt (1+ closeCnt))) );cond (if (= openCnt closeCnt) (setq found t pos (+ pos cnt))) (setq prevChar ch) );while pos );defun ;main work (setq cnt 0 str "" ret '()) (repeat (setq len (strlen json)) (setq ch (substr json (setq cnt (1+ cnt)) 1)) (cond ((or (eq "{" ch) (eq "[" ch)) (setq endPos (EndOfBracket json cnt ch) cnt (1+ cnt) ret (cons (ParseJSON (substr json cnt (- endPos cnt))) ret) str "" cnt endPos) );cond 1 ((eq "\"" ch) (setq endPos (EndOfQuote json cnt) cnt (1+ cnt) ret (cons (substr json cnt (- endPos cnt)) ret) str "" cnt endPos) );cond 2 ((or (eq ":" ch) (eq "," ch)) (setq tmp (read (strcase str))) (cond ((or (eq 'NULL tmp) (eq 'FALSE tmp)) (setq ret (cons nil ret))) ((eq 'TRUE tmp) (setq ret (cons t ret))) ((numberp tmp) (setq ret (cons tmp ret))) ((not (null tmp)) (setq ret (cons (read str) ret))) );cond (setq str "") );cond 3 ((not (member ch '("\n" "\t" "\b" "\r"))) (if (or (eq " " ch) (= (1+ len) cnt)) (progn (setq tmp (read (strcase str))) (cond ((or (eq 'NULL tmp) (eq 'FALSE tmp)) (setq ret (cons nil ret))) ((eq 'TRUE tmp) (setq ret (cons t ret))) ((numberp tmp) (setq ret (cons tmp ret))) ((not (null tmp)) (setq ret (cons (read str) ret))) );cond (setq str "") );progn ;else (setq str (strcat str ch)) );if );cond 4 );cond );repeat (reverse ret) );defun
PLEASE NOTE:
- The one weird caveat to this function, due to its recursive nature and the way it returns items, is that an extra (list ..) is created around the original data. THIS MEANS that you should ALWAYS surround this function with a (car ..) function to return the correct format. (see below)
An Example call:
(setq data (car (ParseJSON->List jsonString)))
If you were to test an example file:
(defun c:TEST ( / str f txt data) (setq str "" f (open "c:\\myFolder\\my sub folder\\example json.txt" "r")) (while (setq txt (read-line f)) (setq str (strcat str txt "\n")) );while (close f) (if (setq data (car (ParseJSON->List str))) (princ data) );if (princ) );defun
Best,
~DD
Solved! Go to Solution.