Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hackassin
GitHub Repository: hackassin/Coursera-Machine-Learning
Path: blob/master/Week 9/Programming Assignment - 8/ex8/lib/jsonlab/loadjson.m
626 views
1
function data = loadjson(fname,varargin)
2
%
3
% data=loadjson(fname,opt)
4
% or
5
% data=loadjson(fname,'param1',value1,'param2',value2,...)
6
%
7
% parse a JSON (JavaScript Object Notation) file or string
8
%
9
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
10
% created on 2011/09/09, including previous works from
11
%
12
% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
13
% created on 2009/11/02
14
% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
15
% created on 2009/03/22
16
% Joel Feenstra:
17
% http://www.mathworks.com/matlabcentral/fileexchange/20565
18
% created on 2008/07/03
19
%
20
% $Id: loadjson.m 460 2015-01-03 00:30:45Z fangq $
21
%
22
% input:
23
% fname: input file name, if fname contains "{}" or "[]", fname
24
% will be interpreted as a JSON string
25
% opt: a struct to store parsing options, opt can be replaced by
26
% a list of ('param',value) pairs - the param string is equivallent
27
% to a field in opt. opt can have the following
28
% fields (first in [.|.] is the default)
29
%
30
% opt.SimplifyCell [0|1]: if set to 1, loadjson will call cell2mat
31
% for each element of the JSON data, and group
32
% arrays based on the cell2mat rules.
33
% opt.FastArrayParser [1|0 or integer]: if set to 1, use a
34
% speed-optimized array parser when loading an
35
% array object. The fast array parser may
36
% collapse block arrays into a single large
37
% array similar to rules defined in cell2mat; 0 to
38
% use a legacy parser; if set to a larger-than-1
39
% value, this option will specify the minimum
40
% dimension to enable the fast array parser. For
41
% example, if the input is a 3D array, setting
42
% FastArrayParser to 1 will return a 3D array;
43
% setting to 2 will return a cell array of 2D
44
% arrays; setting to 3 will return to a 2D cell
45
% array of 1D vectors; setting to 4 will return a
46
% 3D cell array.
47
% opt.ShowProgress [0|1]: if set to 1, loadjson displays a progress bar.
48
%
49
% output:
50
% dat: a cell array, where {...} blocks are converted into cell arrays,
51
% and [...] are converted to arrays
52
%
53
% examples:
54
% dat=loadjson('{"obj":{"string":"value","array":[1,2,3]}}')
55
% dat=loadjson(['examples' filesep 'example1.json'])
56
% dat=loadjson(['examples' filesep 'example1.json'],'SimplifyCell',1)
57
%
58
% license:
59
% BSD, see LICENSE_BSD.txt files for details
60
%
61
% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
62
%
63
64
global pos inStr len esc index_esc len_esc isoct arraytoken
65
66
if(regexp(fname,'[\{\}\]\[]','once'))
67
string=fname;
68
elseif(exist(fname,'file'))
69
fid = fopen(fname,'rb');
70
string = fread(fid,inf,'uint8=>char')';
71
fclose(fid);
72
else
73
error('input file does not exist');
74
end
75
76
pos = 1; len = length(string); inStr = string;
77
isoct=exist('OCTAVE_VERSION','builtin');
78
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
79
jstr=regexprep(inStr,'\\\\',' ');
80
escquote=regexp(jstr,'\\"');
81
arraytoken=sort([arraytoken escquote]);
82
83
% String delimiters and escape chars identified to improve speed:
84
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
85
index_esc = 1; len_esc = length(esc);
86
87
opt=varargin2struct(varargin{:});
88
89
if(jsonopt('ShowProgress',0,opt)==1)
90
opt.progressbar_=waitbar(0,'loading ...');
91
end
92
jsoncount=1;
93
while pos <= len
94
switch(next_char)
95
case '{'
96
data{jsoncount} = parse_object(opt);
97
case '['
98
data{jsoncount} = parse_array(opt);
99
otherwise
100
error_pos('Outer level structure must be an object or an array');
101
end
102
jsoncount=jsoncount+1;
103
end % while
104
105
jsoncount=length(data);
106
if(jsoncount==1 && iscell(data))
107
data=data{1};
108
end
109
110
if(~isempty(data))
111
if(isstruct(data)) % data can be a struct array
112
data=jstruct2array(data);
113
elseif(iscell(data))
114
data=jcell2array(data);
115
end
116
end
117
if(isfield(opt,'progressbar_'))
118
close(opt.progressbar_);
119
end
120
121
%%
122
function newdata=jcell2array(data)
123
len=length(data);
124
newdata=data;
125
for i=1:len
126
if(isstruct(data{i}))
127
newdata{i}=jstruct2array(data{i});
128
elseif(iscell(data{i}))
129
newdata{i}=jcell2array(data{i});
130
end
131
end
132
133
%%-------------------------------------------------------------------------
134
function newdata=jstruct2array(data)
135
fn=fieldnames(data);
136
newdata=data;
137
len=length(data);
138
for i=1:length(fn) % depth-first
139
for j=1:len
140
if(isstruct(getfield(data(j),fn{i})))
141
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
142
end
143
end
144
end
145
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
146
newdata=cell(len,1);
147
for j=1:len
148
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
149
iscpx=0;
150
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
151
if(data(j).x0x5F_ArrayIsComplex_)
152
iscpx=1;
153
end
154
end
155
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
156
if(data(j).x0x5F_ArrayIsSparse_)
157
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
158
dim=data(j).x0x5F_ArraySize_;
159
if(iscpx && size(ndata,2)==4-any(dim==1))
160
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
161
end
162
if isempty(ndata)
163
% All-zeros sparse
164
ndata=sparse(dim(1),prod(dim(2:end)));
165
elseif dim(1)==1
166
% Sparse row vector
167
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
168
elseif dim(2)==1
169
% Sparse column vector
170
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
171
else
172
% Generic sparse array.
173
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
174
end
175
else
176
if(iscpx && size(ndata,2)==4)
177
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
178
end
179
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
180
end
181
end
182
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
183
if(iscpx && size(ndata,2)==2)
184
ndata=complex(ndata(:,1),ndata(:,2));
185
end
186
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
187
end
188
newdata{j}=ndata;
189
end
190
if(len==1)
191
newdata=newdata{1};
192
end
193
end
194
195
%%-------------------------------------------------------------------------
196
function object = parse_object(varargin)
197
parse_char('{');
198
object = [];
199
if next_char ~= '}'
200
while 1
201
str = parseStr(varargin{:});
202
if isempty(str)
203
error_pos('Name of value at position %d cannot be empty');
204
end
205
parse_char(':');
206
val = parse_value(varargin{:});
207
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
208
if next_char == '}'
209
break;
210
end
211
parse_char(',');
212
end
213
end
214
parse_char('}');
215
216
%%-------------------------------------------------------------------------
217
218
function object = parse_array(varargin) % JSON array is written in row-major order
219
global pos inStr isoct
220
parse_char('[');
221
object = cell(0, 1);
222
dim2=[];
223
arraydepth=jsonopt('JSONLAB_ArrayDepth_',1,varargin{:});
224
pbar=jsonopt('progressbar_',-1,varargin{:});
225
226
if next_char ~= ']'
227
if(jsonopt('FastArrayParser',1,varargin{:})>=1 && arraydepth>=jsonopt('FastArrayParser',1,varargin{:}))
228
[endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
229
arraystr=['[' inStr(pos:endpos)];
230
arraystr=regexprep(arraystr,'"_NaN_"','NaN');
231
arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
232
arraystr(arraystr==sprintf('\n'))=[];
233
arraystr(arraystr==sprintf('\r'))=[];
234
%arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
235
if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
236
astr=inStr((e1l+1):(e1r-1));
237
astr=regexprep(astr,'"_NaN_"','NaN');
238
astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
239
astr(astr==sprintf('\n'))=[];
240
astr(astr==sprintf('\r'))=[];
241
astr(astr==' ')='';
242
if(isempty(find(astr=='[', 1))) % array is 2D
243
dim2=length(sscanf(astr,'%f,',[1 inf]));
244
end
245
else % array is 1D
246
astr=arraystr(2:end-1);
247
astr(astr==' ')='';
248
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
249
if(nextidx>=length(astr)-1)
250
object=obj;
251
pos=endpos;
252
parse_char(']');
253
return;
254
end
255
end
256
if(~isempty(dim2))
257
astr=arraystr;
258
astr(astr=='[')='';
259
astr(astr==']')='';
260
astr(astr==' ')='';
261
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
262
if(nextidx>=length(astr)-1)
263
object=reshape(obj,dim2,numel(obj)/dim2)';
264
pos=endpos;
265
parse_char(']');
266
if(pbar>0)
267
waitbar(pos/length(inStr),pbar,'loading ...');
268
end
269
return;
270
end
271
end
272
arraystr=regexprep(arraystr,'\]\s*,','];');
273
else
274
arraystr='[';
275
end
276
try
277
if(isoct && regexp(arraystr,'"','once'))
278
error('Octave eval can produce empty cells for JSON-like input');
279
end
280
object=eval(arraystr);
281
pos=endpos;
282
catch
283
while 1
284
newopt=varargin2struct(varargin{:},'JSONLAB_ArrayDepth_',arraydepth+1);
285
val = parse_value(newopt);
286
object{end+1} = val;
287
if next_char == ']'
288
break;
289
end
290
parse_char(',');
291
end
292
end
293
end
294
if(jsonopt('SimplifyCell',0,varargin{:})==1)
295
try
296
oldobj=object;
297
object=cell2mat(object')';
298
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
299
object=oldobj;
300
elseif(size(object,1)>1 && ndims(object)==2)
301
object=object';
302
end
303
catch
304
end
305
end
306
parse_char(']');
307
308
if(pbar>0)
309
waitbar(pos/length(inStr),pbar,'loading ...');
310
end
311
%%-------------------------------------------------------------------------
312
313
function parse_char(c)
314
global pos inStr len
315
skip_whitespace;
316
if pos > len || inStr(pos) ~= c
317
error_pos(sprintf('Expected %c at position %%d', c));
318
else
319
pos = pos + 1;
320
skip_whitespace;
321
end
322
323
%%-------------------------------------------------------------------------
324
325
function c = next_char
326
global pos inStr len
327
skip_whitespace;
328
if pos > len
329
c = [];
330
else
331
c = inStr(pos);
332
end
333
334
%%-------------------------------------------------------------------------
335
336
function skip_whitespace
337
global pos inStr len
338
while pos <= len && isspace(inStr(pos))
339
pos = pos + 1;
340
end
341
342
%%-------------------------------------------------------------------------
343
function str = parseStr(varargin)
344
global pos inStr len esc index_esc len_esc
345
% len, ns = length(inStr), keyboard
346
if inStr(pos) ~= '"'
347
error_pos('String starting with " expected at position %d');
348
else
349
pos = pos + 1;
350
end
351
str = '';
352
while pos <= len
353
while index_esc <= len_esc && esc(index_esc) < pos
354
index_esc = index_esc + 1;
355
end
356
if index_esc > len_esc
357
str = [str inStr(pos:len)];
358
pos = len + 1;
359
break;
360
else
361
str = [str inStr(pos:esc(index_esc)-1)];
362
pos = esc(index_esc);
363
end
364
nstr = length(str); switch inStr(pos)
365
case '"'
366
pos = pos + 1;
367
if(~isempty(str))
368
if(strcmp(str,'_Inf_'))
369
str=Inf;
370
elseif(strcmp(str,'-_Inf_'))
371
str=-Inf;
372
elseif(strcmp(str,'_NaN_'))
373
str=NaN;
374
end
375
end
376
return;
377
case '\'
378
if pos+1 > len
379
error_pos('End of file reached right after escape character');
380
end
381
pos = pos + 1;
382
switch inStr(pos)
383
case {'"' '\' '/'}
384
str(nstr+1) = inStr(pos);
385
pos = pos + 1;
386
case {'b' 'f' 'n' 'r' 't'}
387
str(nstr+1) = sprintf(['\' inStr(pos)]);
388
pos = pos + 1;
389
case 'u'
390
if pos+4 > len
391
error_pos('End of file reached in escaped unicode character');
392
end
393
str(nstr+(1:6)) = inStr(pos-1:pos+4);
394
pos = pos + 5;
395
end
396
otherwise % should never happen
397
str(nstr+1) = inStr(pos), keyboard
398
pos = pos + 1;
399
end
400
end
401
error_pos('End of file while expecting end of inStr');
402
403
%%-------------------------------------------------------------------------
404
405
function num = parse_number(varargin)
406
global pos inStr len isoct
407
currstr=inStr(pos:end);
408
numstr=0;
409
if(isoct~=0)
410
numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
411
[num, one] = sscanf(currstr, '%f', 1);
412
delta=numstr+1;
413
else
414
[num, one, err, delta] = sscanf(currstr, '%f', 1);
415
if ~isempty(err)
416
error_pos('Error reading number at position %d');
417
end
418
end
419
pos = pos + delta-1;
420
421
%%-------------------------------------------------------------------------
422
423
function val = parse_value(varargin)
424
global pos inStr len
425
true = 1; false = 0;
426
427
pbar=jsonopt('progressbar_',-1,varargin{:});
428
if(pbar>0)
429
waitbar(pos/len,pbar,'loading ...');
430
end
431
432
switch(inStr(pos))
433
case '"'
434
val = parseStr(varargin{:});
435
return;
436
case '['
437
val = parse_array(varargin{:});
438
return;
439
case '{'
440
val = parse_object(varargin{:});
441
if isstruct(val)
442
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
443
val=jstruct2array(val);
444
end
445
elseif isempty(val)
446
val = struct;
447
end
448
return;
449
case {'-','0','1','2','3','4','5','6','7','8','9'}
450
val = parse_number(varargin{:});
451
return;
452
case 't'
453
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
454
val = true;
455
pos = pos + 4;
456
return;
457
end
458
case 'f'
459
if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
460
val = false;
461
pos = pos + 5;
462
return;
463
end
464
case 'n'
465
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
466
val = [];
467
pos = pos + 4;
468
return;
469
end
470
end
471
error_pos('Value expected at position %d');
472
%%-------------------------------------------------------------------------
473
474
function error_pos(msg)
475
global pos inStr len
476
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
477
if poShow(3) == poShow(2)
478
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
479
end
480
msg = [sprintf(msg, pos) ': ' ...
481
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
482
error( ['JSONparser:invalidFormat: ' msg] );
483
484
%%-------------------------------------------------------------------------
485
486
function str = valid_field(str)
487
global isoct
488
% From MATLAB doc: field names must begin with a letter, which may be
489
% followed by any combination of letters, digits, and underscores.
490
% Invalid characters will be converted to underscores, and the prefix
491
% "x0x[Hex code]_" will be added if the first character is not a letter.
492
pos=regexp(str,'^[^A-Za-z]','once');
493
if(~isempty(pos))
494
if(~isoct)
495
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
496
else
497
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
498
end
499
end
500
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
501
if(~isoct)
502
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
503
else
504
pos=regexp(str,'[^0-9A-Za-z_]');
505
if(isempty(pos)) return; end
506
str0=str;
507
pos0=[0 pos(:)' length(str)];
508
str='';
509
for i=1:length(pos)
510
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
511
end
512
if(pos(end)~=length(str))
513
str=[str str0(pos0(end-1)+1:pos0(end))];
514
end
515
end
516
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
517
518
%%-------------------------------------------------------------------------
519
function endpos = matching_quote(str,pos)
520
len=length(str);
521
while(pos<len)
522
if(str(pos)=='"')
523
if(~(pos>1 && str(pos-1)=='\'))
524
endpos=pos;
525
return;
526
end
527
end
528
pos=pos+1;
529
end
530
error('unmatched quotation mark');
531
%%-------------------------------------------------------------------------
532
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
533
global arraytoken
534
level=1;
535
maxlevel=level;
536
endpos=0;
537
bpos=arraytoken(arraytoken>=pos);
538
tokens=str(bpos);
539
len=length(tokens);
540
pos=1;
541
e1l=[];
542
e1r=[];
543
while(pos<=len)
544
c=tokens(pos);
545
if(c==']')
546
level=level-1;
547
if(isempty(e1r)) e1r=bpos(pos); end
548
if(level==0)
549
endpos=bpos(pos);
550
return
551
end
552
end
553
if(c=='[')
554
if(isempty(e1l)) e1l=bpos(pos); end
555
level=level+1;
556
maxlevel=max(maxlevel,level);
557
end
558
if(c=='"')
559
pos=matching_quote(tokens,pos+1);
560
end
561
pos=pos+1;
562
end
563
if(endpos==0)
564
error('unmatched "]"');
565
end
566
567
568