Question
· Jul 18, 2023

Validate JSON string

Hi.

Is there any function to validate JSON string returning status?

Regards,
Matjaž

Product version: IRIS 2023.1
$ZV: IRIS for Windows (x86-64) 2023.1 (Build 229U) Fri Apr 14 2023 17:17:41 EDT
Discussion (13)2
Log in or sign up to continue

I'm not aware of any $ISJSON() or similar named function but you can easily make your own

ClassMethod IsJSON(str)
{
	try { ret:{}.%FromJSON(str) 1 } catch e { ret:e.Code=3 0 throw e }
}

set a="{name:""John Doe"" "
set b="{""name"":""John Doe"" }"

write ##class(some.class).IsJSON(a) --> 0
write ##class(some.class).IsJSON(b) --> 1
write ##class(some.class).IsJSON()  --> <UNDEFINED>zIsJSON+1^...  *str

Python may help

Class dc.Demo
{

ClassMethod ValidateJSON(data As %String = "") As %Status [ Language = python ]
{
import iris
import json
from json import JSONDecodeError

try:
    json.loads(data)
    return iris.system.Status.OK()
except JSONDecodeError as ex:
    return iris.system.Status.Error(5001, f"{ex.msg}: line {ex.lineno} column {ex.colno} (char {ex.pos})")
except Exception as ex:
    return iris.system.Status.Error(5001, repr(ex))
}

}

And result

USER>set status = ##class(dc.Demo).ValidateJSON("{""aa"":123 ""name"": ""value""}") do:'status $system.OBJ.DisplayError(status) 
ERROR #5001: Expecting ',' delimiter: line 1 column 11 (char 10)

USER>set status = ##class(dc.Demo).ValidateJSON("{""aa"": true, ") do:'status $system.OBJ.DisplayError(status) 
ERROR #5001: Expecting property name enclosed in double quotes: line 1 column 14 (char 13)

USER>set status = ##class(dc.Demo).ValidateJSON("{""aa"": wrong ") do:'status $system.OBJ.DisplayError(status) 
ERROR #5001: Expecting value: line 1 column 8 (char 7)

USER>set status = ##class(dc.Demo).ValidateJSON("{""aa"": true}") do:'status $system.OBJ.DisplayError(status)

The ##class(%DynamicAbstractObject).%FromJSON(s) class method, where 's' is a %String containing a JSON array/object or where 's' is a %Stream containing a JSON array/object, will parse the input JSON.  If the parse is successful then it returns an object reference of either %DynamicArray or %DynamicObject classes.  If the parse is unsuccessful then it will signal an error.

The parsing done by the %FromJSON class method is forgiving of at least one common syntax error.  The input string "[0.1,.1]" is not legal JSON because the second array number does not have a digit before the decimal point.  The %FromJSON class method will accept this input and silently supply the missing 0 digit.  If you apply the %ToJSON() method to the resulting %DynamicArray object then the result will be the string "[0.1,0.1]", which is legal JSON syntax.

There is also a %FromJSONFile (filename) class method which will accept a JSON array/object from a file with the specified 'filename'.

May I ask, which Cache or IRIS version you use?

USER>write $zv
IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST
USER>write ##class(%DynamicAbstractObject).%FromJSON("[0.1, .2]")

<THROW>%FromJSON+38^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 7
USER 2e1>

As you see, my IRIS is by far not so forgiving... ☹

Yes, accepts a file too, but as the following test shows, it does not make any difference... a parsing error remains parsing error

USER>set fn="/tmp/mytest.json"

USER>open fn:"nw":1 if $test { use fn write "[0.1, .2]",! close fn write "OK" } else { write "Houston, we have..." }
OK
USER>write {}.%FromJSON(fn)

<THROW>%FromJSON+38^%Library.DynamicAbstractObject.1 *%Exception.General Parsing error 3 Line 1 Offset 7
USER 2e1>

So where is that forgiving Cache/IRIS version?