Skip to content

Commit 7cd46ea

Browse files
committed
[feat] support flags for using jsonlab or jsonencode/jsondecode
1 parent 5b5bc49 commit 7cd46ea

File tree

1 file changed

+64
-16
lines changed

1 file changed

+64
-16
lines changed

jdict.m

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,21 @@
8787
properties
8888
data
8989
end
90+
properties (Access = private)
91+
flags
92+
end
9093
methods
9194

92-
function obj = jdict(val)
93-
if (nargin == 1)
94-
if (ischar(val) && ~isempty(regexp(val, '^https*://', 'once')))
95+
function obj = jdict(val, varargin)
96+
obj.flags = struct('builtinjson', 0);
97+
if (nargin >= 1)
98+
if (~isempty(varargin))
99+
allflags = [varargin(1:2:end); varargin(2:2:end)];
100+
obj.flags = struct(allflags{:});
101+
end
102+
if (ischar(val) && ~isempty(regexpi(val, '^https*://', 'once')))
95103
try
96-
obj.data = loadjson(val);
104+
obj.data = obj.call_('loadjson', val);
97105
catch
98106
obj.data = val;
99107
end
@@ -107,8 +115,9 @@
107115
end
108116
end
109117

110-
% overloading the getter function
111118
function val = subsref(obj, idxkey)
119+
% overloading the getter function jd.('key').('subkey')
120+
112121
oplen = length(idxkey);
113122
val = obj.data;
114123
if (oplen == 1 && strcmp(idxkey.type, '()') && isempty(idxkey.subs))
@@ -117,7 +126,6 @@
117126
i = 1;
118127
while i <= oplen
119128
idx = idxkey(i);
120-
% disp({i, savejson(idx)});
121129
if (isempty(idx.subs))
122130
i = i + 1;
123131
continue
@@ -142,7 +150,7 @@
142150
end
143151
elseif (strcmp(idx.type, '.') && ischar(idx.subs) && strcmp(idx.subs, 'v') && oplen == 1)
144152
i = i + 1;
145-
continue;
153+
continue
146154
elseif ((idx.type == '.' && ischar(idx.subs)) || (iscell(idx.subs) && ~isempty(idx.subs{1})))
147155
onekey = idx.subs;
148156
if (iscell(onekey))
@@ -152,7 +160,7 @@
152160
val = val.data;
153161
end
154162
if (ischar(onekey) && ~isempty(onekey) && onekey(1) == '$')
155-
val = jsonpath(val, onekey);
163+
val = obj.call_('jsonpath', val, onekey);
156164
elseif (isstruct(val))
157165
val = val.(onekey);
158166
elseif (isa(val, 'containers.Map') || isa(val, 'dictionary'))
@@ -170,13 +178,13 @@
170178
end
171179
end
172180

173-
% overloading the setter function, obj.('idxkey')=otherobj
174-
% expanded from rahnema1's sample at https://stackoverflow.com/a/79030223/4271392
175181
function obj = subsasgn(obj, idxkey, otherobj)
182+
% overloading the setter function, obj.('key').('subkey')=otherobj
183+
% expanded from rahnema1's sample at https://stackoverflow.com/a/79030223/4271392
176184
oplen = length(idxkey);
177185
opcell = cell (1, oplen + 1);
178186
if (isempty(obj.data))
179-
obj.data = containers.Map();
187+
obj.data = obj.newkey_();
180188
end
181189
opcell{1} = obj.data;
182190

@@ -196,13 +204,13 @@
196204
if (ischar(idx.subs))
197205
if (((isa(opcell{i}, 'containers.Map') || isa(opcell{i}, 'dictionary')) && ~isKey(opcell{i}, idx.subs)))
198206
idx.type = '()';
199-
opcell{i}(idx.subs) = containers.Map();
207+
opcell{i}(idx.subs) = obj.newkey_();
200208
elseif (isstruct(opcell{i}) && ~isfield(opcell{i}, idx.subs))
201-
opcell{i}.(idx.subs) = containers.Map();
209+
opcell{i}.(idx.subs) = obj.newkey_();
202210
end
203211
end
204212
end
205-
if (exist('OCTAVE_VERSION', 'builtin') ~= 0) && (isa(opcell{i}, 'containers.Map') || isa(opcell{i}, 'dictionary'))
213+
if (isa(opcell{i}, 'containers.Map') || isa(opcell{i}, 'dictionary'))
206214
opcell{i + 1} = opcell{i}(idx.subs);
207215
else
208216
opcell{i + 1} = subsref(opcell{i}, idx);
@@ -218,6 +226,10 @@
218226

219227
for i = oplen - 1:-1:1
220228
idx = idxkey(i);
229+
if (ischar(idx.subs) && strcmp(idx.type, '.') && (isa(opcell{i}, 'containers.Map') || isa(opcell{i}, 'dictionary')))
230+
idx.type = '()';
231+
end
232+
221233
if (ischar(idx.subs) && strcmp(idx.subs, 'v'))
222234
opcell{i} = opcell{i + 1};
223235
continue
@@ -239,14 +251,17 @@
239251
end
240252

241253
function val = tojson(obj, varargin)
242-
val = savejson('', obj.data, 'compact', 1, varargin{:});
254+
% printing underlying data to compact-formed JSON string
255+
val = obj.call_('jsonpath', '', obj.data, 'compact', 1, varargin{:});
243256
end
244257

245258
function obj = fromjson(obj, fname, varargin)
246-
obj.data = loadjd(fname, varargin{:});
259+
% loading diverse data files using loadjd interface in jsonlab
260+
obj.data = obj.call_('loadjd', fname, varargin{:});
247261
end
248262

249263
function val = keys(obj)
264+
% list subfields at the current level
250265
if (isstruct(obj.data))
251266
val = fieldnames(obj.data);
252267
elseif (isa(obj.data, 'containers.Map') || isa(obj.data, 'dictionary'))
@@ -257,6 +272,7 @@
257272
end
258273

259274
function val = len(obj)
275+
% return the number of subfields at the current level
260276
val = length(obj.data);
261277
end
262278

@@ -268,5 +284,37 @@
268284
end
269285
end
270286

287+
function val = newkey_(obj)
288+
% insert new key if does not exist
289+
if (exist('containers.Map'))
290+
val = containers.Map;
291+
else
292+
val = struct;
293+
end
294+
end
295+
296+
function varargout = call_(obj, func, varargin)
297+
% interface to external functions and dependencies
298+
if (~obj.flags.builtinjson)
299+
if (~exist('loadjson', 'file'))
300+
error('you must first install jsonlab (https://github.com/NeuroJSON/jsonlab) or set "BuildinJSON" flag to 1');
301+
end
302+
fhandle = str2func(func);
303+
[varargout{1:nargout}] = fhandle(varargin{:});
304+
else
305+
if (~exist('jsonencode', 'builtin') && ~strcmp(func, 'jsonpath'))
306+
error('jsonencode/jsondecode are not available, please install jsonlab (https://github.com/NeuroJSON/jsonlab) and set "BuiltinJSON" flag to 0');
307+
end
308+
switch func
309+
case 'loadjson'
310+
[varargout{1:nargout}] = jsondecode(webread(varargin{:}));
311+
case 'savejson'
312+
[varargout{1:nargout}] = jsonencode(varargin{:});
313+
case 'jsonpath'
314+
error('please install jsonlab (https://github.com/NeuroJSON/jsonlab) and set "BuiltinJSON" flag to 0');
315+
end
316+
end
317+
end
318+
271319
end
272320
end

0 commit comments

Comments
 (0)