Skip to content

Commit 80bd52f

Browse files
committed
[bug] fix rmfield unable to remove field bug
1 parent 1ec43da commit 80bd52f

File tree

3 files changed

+72
-33
lines changed

3 files changed

+72
-33
lines changed

jdict.m

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
% member functions:
2424
% jd.('cell1').v(i) or jd.('array1').v(2:3) returns specified elements if the element is a cell or array
2525
% jd.('key1').('subkey1').v() returns the underlying hierachical data at the specified subkeys
26-
% jd.tojson() convers the underlying data to a JSON string
27-
% jd.tojson('compression', 'zlib', ...) convers the data to a JSON string with savejson() options
2826
% jd.keys() returns the sub-key names of the object - if it a struct, dictionary or containers.Map - or 1:length(data) if it is an array
2927
% jd.len() returns the length of the sub-keys
3028
% jd.size() returns the dimension vector
@@ -37,6 +35,10 @@
3735
% jd.setschema(schema) sets a JSON Schema for validation (struct, JSON string, URL, or file path)
3836
% jd.getschema() returns the current schema; jd.getschema('json') returns as JSON string
3937
% jd.validate() validates data against schema; [valid, errors] = jd.validate() returns error details
38+
% jd.tojson() convers the underlying data to a JSON string
39+
% jd.fromjson(jsonstr) loading data by parsing a json string
40+
% jd.tobuffer() convers the underlying data to a binary JSON buffer
41+
% jd.frombuffer(binary) loading data by parsing a binary JSON buffer
4042
%
4143
% if using matlab, the .v(...) method can be replaced by bare
4244
% brackets .(...), but in octave, one must use .v(...)
@@ -329,7 +331,7 @@
329331

330332
if (strcmp(idx.type, '.') && isnumeric(idx.subs))
331333
val = val(idx.subs);
332-
elseif ((strcmp(idx.type, '()') || strcmp(idx.type, '.')) && ischar(idx.subs) && ismember(idx.subs, {'tojson', 'fromjson', 'v', 'isKey', 'keys', 'len', 'size', 'setattr', 'getattr', 'setschema', 'getschema', 'validate', 'attr2schema'}) && i < oplen && strcmp(idxkey(i + 1).type, '()'))
334+
elseif ((strcmp(idx.type, '()') || strcmp(idx.type, '.')) && ischar(idx.subs) && ismember(idx.subs, {'tojson', 'fromjson', 'v', 'isKey', 'keys', 'len', 'size', 'setattr', 'getattr', 'setschema', 'getschema', 'validate', 'attr2schema', 'tobuffer', 'frombuffer', 'isfield', 'fieldnames', 'rmfield'}) && i < oplen && strcmp(idxkey(i + 1).type, '()'))
333335
if (strcmp(idx.subs, 'v'))
334336
if (iscell(val) && strcmp(idxkey(i + 1).type, '()'))
335337
idxkey(i + 1).type = '{}';
@@ -348,13 +350,14 @@
348350
tempobj.attr = obj.attr;
349351
tempobj.setschema(obj.schema);
350352
tempobj.currentpath__ = trackpath;
351-
if (obj.flags__.isoctave_ && regexp(OCTAVE_VERSION, '^5\.'))
353+
tempobj.root__ = obj.root__;
354+
if (obj.flags__.isoctave5_)
352355
val = membercall_(tempobj, idx.subs, idxkey(i + 1).subs{:});
353356
else
354357
fhandle = str2func(idx.subs);
355358
val = fhandle(tempobj, idxkey(i + 1).subs{:});
356359
end
357-
if (i == oplen - 1 && ismember(idx.subs, {'isKey', 'tojson', 'getattr', 'getschema', 'setschema', 'validate', 'attr2schema'}))
360+
if (i == oplen - 1 && ismember(idx.subs, {'isKey', 'tojson', 'getattr', 'getschema', 'setschema', 'validate', 'attr2schema', 'isfield'}))
358361
if (strcmp(idx.subs, 'setschema'))
359362
obj.setschema(tempobj.schema);
360363
end
@@ -867,15 +870,26 @@
867870
obj.data = opcell{1};
868871
end
869872

870-
% export data to json, binary JSON, or other over a dozen formats
873+
% export data to json
871874
function val = tojson(obj, varargin)
872875
% printing underlying data to compact-formed JSON string
873-
val = obj.call_('savejd', '', obj, 'compact', 1, varargin{:});
876+
val = obj.call_('savejson', '', obj, 'compact', 1, varargin{:});
874877
end
875878

876-
% load data from over a dozen data formats, including json and binary json
879+
% load data from json
877880
function obj = fromjson(obj, fname, varargin)
878-
obj.data = obj.call_('loadjd', fname, varargin{:});
881+
obj.data = obj.call_('loadjson', fname, varargin{:});
882+
end
883+
884+
% export data to binary JSON buffer
885+
function val = tobuffer(obj, varargin)
886+
% printing underlying data to compact-formed JSON string
887+
val = obj.call_('savebj', '', obj, varargin{:});
888+
end
889+
890+
% load data from binary JSON buffer
891+
function obj = frombuffer(obj, fname, varargin)
892+
obj.data = obj.call_('loadbj', fname, varargin{:});
879893
end
880894

881895
function val = keys(obj)
@@ -909,17 +923,20 @@
909923
end
910924

911925
% remove specified key or element
912-
function val = rmfield(obj, key)
913-
% list subfields at the current level
914-
if (isstruct(obj.data))
915-
val = rmfield(obj.data, key);
916-
elseif (ismap_(obj.flags__, obj.data))
917-
val = remove(obj.data, key);
918-
elseif (iscell(obj.data))
919-
obj.data = builtin('subsasgn', obj.data, struct('type', '{}', 'subs', {{key}}), []);
926+
function obj = rmfield(obj, key)
927+
currentpath = obj.currentpath__;
928+
root = obj.root__;
929+
930+
% Build path to the key to delete
931+
escapedkey = esckey_(key);
932+
if strcmp(currentpath, char(36))
933+
targetpath = [char(36) '.' escapedkey];
920934
else
921-
obj.data = builtin('subsasgn', obj.data, struct('type', '()', 'subs', {{key}}), []);
935+
targetpath = [currentpath '.' escapedkey];
922936
end
937+
938+
% Use jsonpath to delete from root's data
939+
root.data = obj.call_('jsonpath', root.data, targetpath, jdict([], 'kind', '_deleted_', 'schema', struct('type', 'null')));
923940
end
924941

925942
% return the number of subfields or array length
@@ -954,10 +971,6 @@
954971

955972
function val = membercall_(obj, method, varargin)
956973
switch method
957-
case 'tojson'
958-
val = tojson(obj);
959-
case 'fromjson'
960-
val = fromjson(obj, varargin{:});
961974
case 'v'
962975
val = v(obj);
963976
case 'isKey'
@@ -980,6 +993,20 @@
980993
val = validate(obj, varargin{:});
981994
case 'attr2schema'
982995
val = attr2schema(obj, varargin{:});
996+
case 'tojson'
997+
val = tojson(obj);
998+
case 'fromjson'
999+
val = fromjson(obj, varargin{:});
1000+
case 'tobuffer'
1001+
val = tobuffer(obj);
1002+
case 'frombuffer'
1003+
val = frombuffer(obj, varargin{:});
1004+
case 'fieldnames'
1005+
val = fieldnames(obj);
1006+
case 'isfield'
1007+
val = isfield(obj, varargin{:});
1008+
case 'rmfield'
1009+
val = rmfield(obj, varargin{:});
9831010
end
9841011
end
9851012

@@ -1001,8 +1028,8 @@
10011028
[varargout{1:nargout}] = jsondecode(webread(varargin{:}));
10021029
case 'savejson'
10031030
[varargout{1:nargout}] = jsonencode(varargin{:});
1004-
case 'jsonpath'
1005-
error('please install jsonlab (https://github.com/NeuroJSON/jsonlab) and set "BuiltinJSON" flag to 0');
1031+
case {'jsonpath', 'jsonschema'}
1032+
error('please install jsonlab (https://github.com/NeuroJSON/jsonlab)');
10061033
end
10071034
end
10081035
end
@@ -1319,6 +1346,7 @@
13191346
cachedflags = struct();
13201347
cachedflags.builtinjson = 0;
13211348
cachedflags.isoctave_ = exist('OCTAVE_VERSION', 'builtin') ~= 0;
1349+
cachedflags.isoctave5_ = (cachedflags.isoctave_ && regexp(OCTAVE_VERSION, '^5\.'));
13221350
try
13231351
containers.Map();
13241352
cachedflags.hasmap_ = true;

jsonpath.m

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,22 @@
204204
end
205205

206206
function data = setfield_safe(data, fieldname, value)
207-
if isstruct(data)
208-
data.(fieldname) = value;
209-
elseif isa(data, 'containers.Map') || isa(data, 'dictionary')
210-
data(fieldname) = value;
207+
if (isa(value, 'jdict') && ~isempty(value{'kind'}) && strcmp(value{'kind'}, '_deleted_'))
208+
if isstruct(data) && isfield(data, fieldname)
209+
data = rmfield(data, fieldname);
210+
elseif (isa(data, 'containers.Map') || isa(data, 'dictionary')) && isKey(data, fieldname)
211+
data = remove(data, fieldname);
212+
else
213+
idx = struct('type', '.', 'subs', fieldname);
214+
data = subsasgn(data, idx, []);
215+
end
211216
else
212-
idx = struct('type', '.', 'subs', fieldname);
213-
data = subsasgn(data, idx, value);
217+
if isstruct(data)
218+
data.(fieldname) = value;
219+
elseif isa(data, 'containers.Map') || isa(data, 'dictionary')
220+
data(fieldname) = value;
221+
else
222+
idx = struct('type', '.', 'subs', fieldname);
223+
data = subsasgn(data, idx, value);
224+
end
214225
end

savebj.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
% "_ArrayZipData_": the binary stream of
9191
% the compressed binary array data WITHOUT
9292
% 'base64' encoding
93-
% CompressArraySize [100|int]: only to compress an array if the total
93+
% CompressArraySize [300|int]: only to compress an array if the total
9494
% element count is larger than this number.
9595
% CompressStringSize [inf|int]: only to compress a string if the total
9696
% element count is larger than this number.
@@ -180,10 +180,10 @@
180180
end
181181

182182
opt.isoctave = isoctavemesh;
183-
opt.compression = jsonopt('Compression', '', opt);
183+
opt.compression = jsonopt('Compression', 'zlib', opt);
184184
opt.nestarray = jsonopt('NestArray', 0, opt);
185185
opt.formatversion = jsonopt('FormatVersion', 4, opt);
186-
opt.compressarraysize = jsonopt('CompressArraySize', 100, opt);
186+
opt.compressarraysize = jsonopt('CompressArraySize', 300, opt);
187187
opt.compressstringsize = jsonopt('CompressStringSize', inf, opt);
188188
opt.singletcell = jsonopt('SingletCell', 1, opt);
189189
opt.singletarray = jsonopt('SingletArray', 0, opt);

0 commit comments

Comments
 (0)