Path: blob/master/Week 9/Programming Assignment - 8/ex8/lib/jsonlab/savejson.m
626 views
function json=savejson(rootname,obj,varargin)1%2% json=savejson(rootname,obj,filename)3% or4% json=savejson(rootname,obj,opt)5% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)6%7% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript8% Object Notation) string9%10% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)11% created on 2011/09/0912%13% $Id: savejson.m 460 2015-01-03 00:30:45Z fangq $14%15% input:16% rootname: the name of the root-object, when set to '', the root name17% is ignored, however, when opt.ForceRootName is set to 1 (see below),18% the MATLAB variable name will be used as the root name.19% obj: a MATLAB object (array, cell, cell array, struct, struct array).20% filename: a string for the file name to save the output JSON data.21% opt: a struct for additional options, ignore to use default values.22% opt can have the following fields (first in [.|.] is the default)23%24% opt.FileName [''|string]: a file name to save the output JSON data25% opt.FloatFormat ['%.10g'|string]: format to show each numeric element26% of a 1D/2D array;27% opt.ArrayIndent [1|0]: if 1, output explicit data array with28% precedent indentation; if 0, no indentation29% opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D30% array in JSON array format; if sets to 1, an31% array will be shown as a struct with fields32% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for33% sparse arrays, the non-zero elements will be34% saved to _ArrayData_ field in triplet-format i.e.35% (ix,iy,val) and "_ArrayIsSparse_" will be added36% with a value of 1; for a complex array, the37% _ArrayData_ array will include two columns38% (4 for sparse) to record the real and imaginary39% parts, and also "_ArrayIsComplex_":1 is added.40% opt.ParseLogical [0|1]: if this is set to 1, logical array elem41% will use true/false rather than 1/0.42% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single43% numerical element will be shown without a square44% bracket, unless it is the root object; if 0, square45% brackets are forced for any numerical arrays.46% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson47% will use the name of the passed obj variable as the48% root object name; if obj is an expression and49% does not have a name, 'root' will be used; if this50% is set to 0 and rootname is empty, the root level51% will be merged down to the lower level.52% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern53% to represent +/-Inf. The matched pattern is '([-+]*)Inf'54% and $1 represents the sign. For those who want to use55% 1e999 to represent Inf, they can set opt.Inf to '$11e999'56% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern57% to represent NaN58% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),59% for example, if opt.JSONP='foo', the JSON data is60% wrapped inside a function call as 'foo(...);'61% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson62% back to the string form63% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.64% opt.Compact [0|1]: 1- out compact JSON format (remove all newlines and tabs)65%66% opt can be replaced by a list of ('param',value) pairs. The param67% string is equivallent to a field in opt and is case sensitive.68% output:69% json: a string in the JSON format (see http://json.org)70%71% examples:72% jsonmesh=struct('MeshNode',[0 0 0;1 0 0;0 1 0;1 1 0;0 0 1;1 0 1;0 1 1;1 1 1],...73% 'MeshTetra',[1 2 4 8;1 3 4 8;1 2 6 8;1 5 6 8;1 5 7 8;1 3 7 8],...74% 'MeshTri',[1 2 4;1 2 6;1 3 4;1 3 7;1 5 6;1 5 7;...75% 2 8 4;2 8 6;3 8 4;3 8 7;5 8 6;5 8 7],...76% 'MeshCreator','FangQ','MeshTitle','T6 Cube',...77% 'SpecialData',[nan, inf, -inf]);78% savejson('jmesh',jsonmesh)79% savejson('',jsonmesh,'ArrayIndent',0,'FloatFormat','\t%.5g')80%81% license:82% BSD, see LICENSE_BSD.txt files for details83%84% -- this function is part of JSONLab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)85%8687if(nargin==1)88varname=inputname(1);89obj=rootname;90if(isempty(varname))91varname='root';92end93rootname=varname;94else95varname=inputname(2);96end97if(length(varargin)==1 && ischar(varargin{1}))98opt=struct('FileName',varargin{1});99else100opt=varargin2struct(varargin{:});101end102opt.IsOctave=exist('OCTAVE_VERSION','builtin');103rootisarray=0;104rootlevel=1;105forceroot=jsonopt('ForceRootName',0,opt);106if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)107rootisarray=1;108rootlevel=0;109else110if(isempty(rootname))111rootname=varname;112end113end114if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)115rootname='root';116end117118whitespaces=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));119if(jsonopt('Compact',0,opt)==1)120whitespaces=struct('tab','','newline','','sep',',');121end122if(~isfield(opt,'whitespaces_'))123opt.whitespaces_=whitespaces;124end125126nl=whitespaces.newline;127128json=obj2json(rootname,obj,rootlevel,opt);129if(rootisarray)130json=sprintf('%s%s',json,nl);131else132json=sprintf('{%s%s%s}\n',nl,json,nl);133end134135jsonp=jsonopt('JSONP','',opt);136if(~isempty(jsonp))137json=sprintf('%s(%s);%s',jsonp,json,nl);138end139140% save to a file if FileName is set, suggested by Patrick Rapin141if(~isempty(jsonopt('FileName','',opt)))142if(jsonopt('SaveBinary',0,opt)==1)143fid = fopen(opt.FileName, 'wb');144fwrite(fid,json);145else146fid = fopen(opt.FileName, 'wt');147fwrite(fid,json,'char');148end149fclose(fid);150end151152%%-------------------------------------------------------------------------153function txt=obj2json(name,item,level,varargin)154155if(iscell(item))156txt=cell2json(name,item,level,varargin{:});157elseif(isstruct(item))158txt=struct2json(name,item,level,varargin{:});159elseif(ischar(item))160txt=str2json(name,item,level,varargin{:});161else162txt=mat2json(name,item,level,varargin{:});163end164165%%-------------------------------------------------------------------------166function txt=cell2json(name,item,level,varargin)167txt='';168if(~iscell(item))169error('input is not a cell');170end171172dim=size(item);173if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now174item=reshape(item,dim(1),numel(item)/dim(1));175dim=size(item);176end177len=numel(item);178ws=jsonopt('whitespaces_',struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n')),varargin{:});179padding0=repmat(ws.tab,1,level);180padding2=repmat(ws.tab,1,level+1);181nl=ws.newline;182if(len>1)183if(~isempty(name))184txt=sprintf('%s"%s": [%s',padding0, checkname(name,varargin{:}),nl); name='';185else186txt=sprintf('%s[%s',padding0,nl);187end188elseif(len==0)189if(~isempty(name))190txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name='';191else192txt=sprintf('%s[]',padding0);193end194end195for j=1:dim(2)196if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end197for i=1:dim(1)198txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));199if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end200end201if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end202if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end203%if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end204end205if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end206207%%-------------------------------------------------------------------------208function txt=struct2json(name,item,level,varargin)209txt='';210if(~isstruct(item))211error('input is not a struct');212end213dim=size(item);214if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now215item=reshape(item,dim(1),numel(item)/dim(1));216dim=size(item);217end218len=numel(item);219ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'));220ws=jsonopt('whitespaces_',ws,varargin{:});221padding0=repmat(ws.tab,1,level);222padding2=repmat(ws.tab,1,level+1);223padding1=repmat(ws.tab,1,level+(dim(1)>1)+(len>1));224nl=ws.newline;225226if(~isempty(name))227if(len>1) txt=sprintf('%s"%s": [%s',padding0,checkname(name,varargin{:}),nl); end228else229if(len>1) txt=sprintf('%s[%s',padding0,nl); end230end231for j=1:dim(2)232if(dim(1)>1) txt=sprintf('%s%s[%s',txt,padding2,nl); end233for i=1:dim(1)234names = fieldnames(item(i,j));235if(~isempty(name) && len==1)236txt=sprintf('%s%s"%s": {%s',txt,padding1, checkname(name,varargin{:}),nl);237else238txt=sprintf('%s%s{%s',txt,padding1,nl);239end240if(~isempty(names))241for e=1:length(names)242txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...243names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));244if(e<length(names)) txt=sprintf('%s%s',txt,','); end245txt=sprintf('%s%s',txt,nl);246end247end248txt=sprintf('%s%s}',txt,padding1);249if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end250end251if(dim(1)>1) txt=sprintf('%s%s%s]',txt,nl,padding2); end252if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',%s',nl)); end253end254if(len>1) txt=sprintf('%s%s%s]',txt,nl,padding0); end255256%%-------------------------------------------------------------------------257function txt=str2json(name,item,level,varargin)258txt='';259if(~ischar(item))260error('input is not a string');261end262item=reshape(item, max(size(item),[1 0]));263len=size(item,1);264ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));265ws=jsonopt('whitespaces_',ws,varargin{:});266padding1=repmat(ws.tab,1,level);267padding0=repmat(ws.tab,1,level+1);268nl=ws.newline;269sep=ws.sep;270271if(~isempty(name))272if(len>1) txt=sprintf('%s"%s": [%s',padding1,checkname(name,varargin{:}),nl); end273else274if(len>1) txt=sprintf('%s[%s',padding1,nl); end275end276isoct=jsonopt('IsOctave',0,varargin{:});277for e=1:len278if(isoct)279val=regexprep(item(e,:),'\\','\\');280val=regexprep(val,'"','\"');281val=regexprep(val,'^"','\"');282else283val=regexprep(item(e,:),'\\','\\\\');284val=regexprep(val,'"','\\"');285val=regexprep(val,'^"','\\"');286end287val=escapejsonstring(val);288if(len==1)289obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];290if(isempty(name)) obj=['"',val,'"']; end291txt=sprintf('%s%s%s%s',txt,padding1,obj);292else293txt=sprintf('%s%s%s%s',txt,padding0,['"',val,'"']);294end295if(e==len) sep=''; end296txt=sprintf('%s%s',txt,sep);297end298if(len>1) txt=sprintf('%s%s%s%s',txt,nl,padding1,']'); end299300%%-------------------------------------------------------------------------301function txt=mat2json(name,item,level,varargin)302if(~isnumeric(item) && ~islogical(item))303error('input is not an array');304end305ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));306ws=jsonopt('whitespaces_',ws,varargin{:});307padding1=repmat(ws.tab,1,level);308padding0=repmat(ws.tab,1,level+1);309nl=ws.newline;310sep=ws.sep;311312if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...313isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))314if(isempty(name))315txt=sprintf('%s{%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...316padding1,nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);317else318txt=sprintf('%s"%s": {%s%s"_ArrayType_": "%s",%s%s"_ArraySize_": %s,%s',...319padding1,checkname(name,varargin{:}),nl,padding0,class(item),nl,padding0,regexprep(mat2str(size(item)),'\s+',','),nl);320end321else322if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1 && level>0)323numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');324else325numtxt=matdata2json(item,level+1,varargin{:});326end327if(isempty(name))328txt=sprintf('%s%s',padding1,numtxt);329else330if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)331txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);332else333txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);334end335end336return;337end338dataformat='%s%s%s%s%s';339340if(issparse(item))341[ix,iy]=find(item);342data=full(item(find(item)));343if(~isreal(item))344data=[real(data(:)),imag(data(:))];345if(size(item,1)==1)346% Kludge to have data's 'transposedness' match item's.347% (Necessary for complex row vector handling below.)348data=data';349end350txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);351end352txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sep);353if(size(item,1)==1)354% Row vector, store only column indices.355txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...356matdata2json([iy(:),data'],level+2,varargin{:}), nl);357elseif(size(item,2)==1)358% Column vector, store only row indices.359txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...360matdata2json([ix,data],level+2,varargin{:}), nl);361else362% General case, store row and column indices.363txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...364matdata2json([ix,iy,data],level+2,varargin{:}), nl);365end366else367if(isreal(item))368txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...369matdata2json(item(:)',level+2,varargin{:}), nl);370else371txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sep);372txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...373matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), nl);374end375end376txt=sprintf('%s%s%s',txt,padding1,'}');377378%%-------------------------------------------------------------------------379function txt=matdata2json(mat,level,varargin)380381ws=struct('tab',sprintf('\t'),'newline',sprintf('\n'),'sep',sprintf(',\n'));382ws=jsonopt('whitespaces_',ws,varargin{:});383tab=ws.tab;384nl=ws.newline;385386if(size(mat,1)==1)387pre='';388post='';389level=level-1;390else391pre=sprintf('[%s',nl);392post=sprintf('%s%s]',nl,repmat(tab,1,level-1));393end394395if(isempty(mat))396txt='null';397return;398end399floatformat=jsonopt('FloatFormat','%.10g',varargin{:});400%if(numel(mat)>1)401formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],%s',nl)]];402%else403% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];404%end405406if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)407formatstr=[repmat(tab,1,level) formatstr];408end409410txt=sprintf(formatstr,mat');411txt(end-length(nl):end)=[];412if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)413txt=regexprep(txt,'1','true');414txt=regexprep(txt,'0','false');415end416%txt=regexprep(mat2str(mat),'\s+',',');417%txt=regexprep(txt,';',sprintf('],\n['));418% if(nargin>=2 && size(mat,1)>1)419% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);420% end421txt=[pre txt post];422if(any(isinf(mat(:))))423txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));424end425if(any(isnan(mat(:))))426txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));427end428429%%-------------------------------------------------------------------------430function newname=checkname(name,varargin)431isunpack=jsonopt('UnpackHex',1,varargin{:});432newname=name;433if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))434return435end436if(isunpack)437isoct=jsonopt('IsOctave',0,varargin{:});438if(~isoct)439newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');440else441pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');442pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');443if(isempty(pos)) return; end444str0=name;445pos0=[0 pend(:)' length(name)];446newname='';447for i=1:length(pos)448newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];449end450if(pos(end)~=length(name))451newname=[newname str0(pos0(end-1)+1:pos0(end))];452end453end454end455456%%-------------------------------------------------------------------------457function newstr=escapejsonstring(str)458newstr=str;459isoct=exist('OCTAVE_VERSION','builtin');460if(isoct)461vv=sscanf(OCTAVE_VERSION,'%f');462if(vv(1)>=3.8) isoct=0; end463end464if(isoct)465escapechars={'\a','\f','\n','\r','\t','\v'};466for i=1:length(escapechars);467newstr=regexprep(newstr,escapechars{i},escapechars{i});468end469else470escapechars={'\a','\b','\f','\n','\r','\t','\v'};471for i=1:length(escapechars);472newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));473end474end475476477