I thaught that returning an association list was closer to the Json object structure (key-value pairs), and the access to data can be done with the classical: (cdr (assoc key)).
The attached assembly defines two LISP functions json->list (same as previous) and json->alist.
(setq str
"{ \"prop1\":\"val1\",
\"prop2\":123.4,
\"prop3\":[
{ \"a\":null,\"b\":true },
{ \"c\":1234,\"d\":false }
]
}"
)
Results:
_$ (json->list str)
("prop1" "val1" "prop2" 123.4 "prop3" (("a" nil "b" T) ("c" 1234 "d" nil)))
_$ (json->alist str)
(("prop1" . "val1")
("prop2" . 123.4)
("prop3" (("a") ("b" . T)) (("c" . 1234) ("d")))
)
C# code for the json->alist function:
[LispFunction("JSON->AList")]
public static ResultBuffer JasonToAssocList(ResultBuffer resbuf)
{
if (resbuf == null)
return null;
var args = resbuf.AsArray();
if (args.Length != 1)
return null;
if (args[0].TypeCode != (int)LispDataType.Text)
return null;
string arg = (string)args[0].Value;
try
{
var dict = new JavaScriptSerializer().DeserializeObject(arg)
as Dictionary<string, dynamic>;
var result = new ResultBuffer();
AddDictionary(result, dict);
return result;
}
catch (System.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Core.Application.ShowAlertDialog(
$"Error: {ex.Message}");
return null;
}
}
private static void AddDictionary(ResultBuffer result, Dictionary<string, dynamic> dict)
{
foreach (var pair in dict)
{
result.Add(new TypedValue((int)LispDataType.ListBegin));
result.Add(new TypedValue((int)LispDataType.Text, pair.Key));
switch (pair.Value)
{
case null:
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
case string s:
result.Add(new TypedValue((int)LispDataType.Text, s));
result.Add(new TypedValue((int)LispDataType.DottedPair));
break;
case int i:
result.Add(new TypedValue((int)LispDataType.Int32, i));
result.Add(new TypedValue((int)LispDataType.DottedPair));
break;
case decimal d:
result.Add(new TypedValue((int)LispDataType.Double, d));
result.Add(new TypedValue((int)LispDataType.DottedPair));
break;
case bool b when !b:
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
case bool b when b:
result.Add(new TypedValue((int)LispDataType.T_atom));
result.Add(new TypedValue((int)LispDataType.DottedPair));
break;
case Dictionary<string, object> d:
result.Add(new TypedValue((int)LispDataType.ListBegin));
AddDictionary(result, d);
result.Add(new TypedValue((int)LispDataType.ListEnd));
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
case object[] a:
foreach (var o in a) AddValue(result, o);
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
default:
break;
}
}
}
private static void AddValue(ResultBuffer result, object obj)
{
switch (obj)
{
case null:
result.Add(new TypedValue((int)LispDataType.Nil));
break;
case string s:
result.Add(new TypedValue((int)LispDataType.Text, s));
break;
case int i:
result.Add(new TypedValue((int)LispDataType.Int32, i));
break;
case decimal d:
result.Add(new TypedValue((int)LispDataType.Double, d));
break;
case bool b when !b:
result.Add(new TypedValue((int)LispDataType.Nil));
break;
case bool b when b:
result.Add(new TypedValue((int)LispDataType.T_atom));
break;
case Dictionary<string, object> d:
result.Add(new TypedValue((int)LispDataType.ListBegin));
AddDictionary(result, d);
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
case object[] a:
result.Add(new TypedValue((int)LispDataType.ListBegin));
foreach (var o in a) AddValue(result, o);
result.Add(new TypedValue((int)LispDataType.ListEnd));
break;
default:
break;
}
}