mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 11:07:48 +00:00
Add a advanced example
It uses its own API which I packed between MTApi5 and MatLab. Possible that this is useless, but errors from the .NET assembly are more tradable.
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
===============================================================================
|
||||
= JSONlab =
|
||||
= An open-source MATLAB/Octave JSON encoder and decoder =
|
||||
===============================================================================
|
||||
|
||||
*Copyright (c) 2011-2014 Qianqian Fang <fangq at nmr.mgh.harvard.edu>
|
||||
*License: Simplified BSD License
|
||||
*Version: 1.0.0-RC1 (Optimus - RC1)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Table of Content:
|
||||
|
||||
I. Introduction
|
||||
II. Installation
|
||||
III.Using JSONlab
|
||||
IV. Known Issues and TODOs
|
||||
V. Contribution and feedback
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
I. Introduction
|
||||
|
||||
JSON ([http://www.json.org/ JavaScript Object Notation]) is a highly portable,
|
||||
human-readable and "[http://en.wikipedia.org/wiki/JSON fat-free]" text format
|
||||
to represent complex and hierarchical data. It is as powerful as
|
||||
[http://en.wikipedia.org/wiki/XML XML], but less verbose. JSON format is widely
|
||||
used for data-exchange in applications, and is essential for the wild success
|
||||
of [http://en.wikipedia.org/wiki/Ajax_(programming) Ajax] and
|
||||
[http://en.wikipedia.org/wiki/Web_2.0 Web2.0].
|
||||
|
||||
UBJSON (Universal Binary JSON) is a binary JSON format, specifically
|
||||
optimized for compact file size and better performance while keeping
|
||||
the semantics as simple as the text-based JSON format. Using the UBJSON
|
||||
format allows to wrap complex binary data in a flexible and extensible
|
||||
structure, making it possible to process complex and large dataset
|
||||
without accuracy loss due to text conversions.
|
||||
|
||||
We envision that both JSON and its binary version will serve as part of
|
||||
the mainstream data-exchange formats for scientific research in the future.
|
||||
It will provide the flexibility and generality achieved by other popular
|
||||
general-purpose file specifications, such as
|
||||
[http://www.hdfgroup.org/HDF5/whatishdf5.html HDF5], with significantly
|
||||
reduced complexity and enhanced performance.
|
||||
|
||||
JSONlab is a free and open-source implementation of a JSON/UBJSON encoder
|
||||
and a decoder in the native MATLAB language. It can be used to convert a MATLAB
|
||||
data structure (array, struct, cell, struct array and cell array) into
|
||||
JSON/UBJSON formatted strings, or to decode a JSON/UBJSON file into MATLAB
|
||||
data structure. JSONlab supports both MATLAB and
|
||||
[http://www.gnu.org/software/octave/ GNU Octave] (a free MATLAB clone).
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
II. Installation
|
||||
|
||||
The installation of JSONlab is no different than any other simple
|
||||
MATLAB toolbox. You only need to download/unzip the JSONlab package
|
||||
to a folder, and add the folder's path to MATLAB/Octave's path list
|
||||
by using the following command:
|
||||
|
||||
addpath('/path/to/jsonlab');
|
||||
|
||||
If you want to add this path permanently, you need to type "pathtool",
|
||||
browse to the jsonlab root folder and add to the list, then click "Save".
|
||||
Then, run "rehash" in MATLAB, and type "which loadjson", if you see an
|
||||
output, that means JSONlab is installed for MATLAB/Octave.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
III.Using JSONlab
|
||||
|
||||
JSONlab provides two functions, loadjson.m -- a MATLAB->JSON decoder,
|
||||
and savejson.m -- a MATLAB->JSON encoder, for the text-based JSON, and
|
||||
two equivallent functions -- loadubjson and saveubjson for the binary
|
||||
JSON. The detailed help info for the four functions can be found below:
|
||||
|
||||
=== loadjson.m ===
|
||||
<pre>
|
||||
data=loadjson(fname,opt)
|
||||
or
|
||||
data=loadjson(fname,'param1',value1,'param2',value2,...)
|
||||
|
||||
parse a JSON (JavaScript Object Notation) file or string
|
||||
|
||||
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
date: 2011/09/09
|
||||
Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
|
||||
date: 2009/11/02
|
||||
François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
|
||||
date: 2009/03/22
|
||||
Joel Feenstra:
|
||||
http://www.mathworks.com/matlabcentral/fileexchange/20565
|
||||
date: 2008/07/03
|
||||
|
||||
$Id: loadjson.m 437 2014-09-15 18:59:36Z fangq $
|
||||
|
||||
input:
|
||||
fname: input file name, if fname contains "{}" or "[]", fname
|
||||
will be interpreted as a JSON string
|
||||
opt: a struct to store parsing options, opt can be replaced by
|
||||
a list of ('param',value) pairs. The param string is equivallent
|
||||
to a field in opt.
|
||||
|
||||
output:
|
||||
dat: a cell array, where {...} blocks are converted into cell arrays,
|
||||
and [...] are converted to arrays
|
||||
</pre>
|
||||
|
||||
=== savejson.m ===
|
||||
|
||||
<pre>
|
||||
json=savejson(rootname,obj,filename)
|
||||
or
|
||||
json=savejson(rootname,obj,opt)
|
||||
json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
|
||||
|
||||
convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
|
||||
Object Notation) string
|
||||
|
||||
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
created on 2011/09/09
|
||||
|
||||
$Id: savejson.m 439 2014-09-17 05:31:08Z fangq $
|
||||
|
||||
input:
|
||||
rootname: name of the root-object, if set to '', will use variable name
|
||||
obj: a MATLAB object (array, cell, cell array, struct, struct array)
|
||||
filename: a string for the file name to save the output JSON data
|
||||
opt: a struct for additional options, use [] if all use default
|
||||
opt can have the following fields (first in [.|.] is the default)
|
||||
|
||||
opt.FileName [''|string]: a file name to save the output JSON data
|
||||
opt.FloatFormat ['%.10g'|string]: format to show each numeric element
|
||||
of a 1D/2D array;
|
||||
opt.ArrayIndent [1|0]: if 1, output explicit data array with
|
||||
precedent indentation; if 0, no indentation
|
||||
opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
|
||||
array in JSON array format; if sets to 1, an
|
||||
array will be shown as a struct with fields
|
||||
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
|
||||
sparse arrays, the non-zero elements will be
|
||||
saved to _ArrayData_ field in triplet-format i.e.
|
||||
(ix,iy,val) and "_ArrayIsSparse_" will be added
|
||||
with a value of 1; for a complex array, the
|
||||
_ArrayData_ array will include two columns
|
||||
(4 for sparse) to record the real and imaginary
|
||||
parts, and also "_ArrayIsComplex_":1 is added.
|
||||
opt.ParseLogical [0|1]: if this is set to 1, logical array elem
|
||||
will use true/false rather than 1/0.
|
||||
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
|
||||
numerical element will be shown without a square
|
||||
bracket, unless it is the root object; if 0, square
|
||||
brackets are forced for any numerical arrays.
|
||||
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
|
||||
will use the name of the passed obj variable as the
|
||||
root object name; if obj is an expression and
|
||||
does not have a name, 'root' will be used; if this
|
||||
is set to 0 and rootname is empty, the root level
|
||||
will be merged down to the lower level.
|
||||
opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
|
||||
to represent +/-Inf. The matched pattern is '([-+]*)Inf'
|
||||
and $1 represents the sign. For those who want to use
|
||||
1e999 to represent Inf, they can set opt.Inf to '$11e999'
|
||||
opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
|
||||
to represent NaN
|
||||
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
|
||||
for example, if opt.JSON='foo', the JSON data is
|
||||
wrapped inside a function call as 'foo(...);'
|
||||
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
|
||||
back to the string form
|
||||
opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
|
||||
opt can be replaced by a list of ('param',value) pairs. The param
|
||||
string is equivallent to a field in opt.
|
||||
output:
|
||||
json: a string in the JSON format (see http://json.org)
|
||||
|
||||
examples:
|
||||
a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
|
||||
'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
|
||||
savejson('mesh',a)
|
||||
savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
|
||||
</pre>
|
||||
|
||||
=== loadubjson.m ===
|
||||
|
||||
<pre>
|
||||
data=loadubjson(fname,opt)
|
||||
or
|
||||
data=loadubjson(fname,'param1',value1,'param2',value2,...)
|
||||
|
||||
parse a JSON (JavaScript Object Notation) file or string
|
||||
|
||||
authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
date: 2013/08/01
|
||||
|
||||
$Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
|
||||
|
||||
input:
|
||||
fname: input file name, if fname contains "{}" or "[]", fname
|
||||
will be interpreted as a UBJSON string
|
||||
opt: a struct to store parsing options, opt can be replaced by
|
||||
a list of ('param',value) pairs. The param string is equivallent
|
||||
to a field in opt.
|
||||
|
||||
output:
|
||||
dat: a cell array, where {...} blocks are converted into cell arrays,
|
||||
and [...] are converted to arrays
|
||||
</pre>
|
||||
|
||||
=== saveubjson.m ===
|
||||
|
||||
<pre>
|
||||
json=saveubjson(rootname,obj,filename)
|
||||
or
|
||||
json=saveubjson(rootname,obj,opt)
|
||||
json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
|
||||
|
||||
convert a MATLAB object (cell, struct or array) into a Universal
|
||||
Binary JSON (UBJSON) binary string
|
||||
|
||||
author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
created on 2013/08/17
|
||||
|
||||
$Id: saveubjson.m 439 2014-09-17 05:31:08Z fangq $
|
||||
|
||||
input:
|
||||
rootname: name of the root-object, if set to '', will use variable name
|
||||
obj: a MATLAB object (array, cell, cell array, struct, struct array)
|
||||
filename: a string for the file name to save the output JSON data
|
||||
opt: a struct for additional options, use [] if all use default
|
||||
opt can have the following fields (first in [.|.] is the default)
|
||||
|
||||
opt.FileName [''|string]: a file name to save the output JSON data
|
||||
opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
|
||||
array in JSON array format; if sets to 1, an
|
||||
array will be shown as a struct with fields
|
||||
"_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
|
||||
sparse arrays, the non-zero elements will be
|
||||
saved to _ArrayData_ field in triplet-format i.e.
|
||||
(ix,iy,val) and "_ArrayIsSparse_" will be added
|
||||
with a value of 1; for a complex array, the
|
||||
_ArrayData_ array will include two columns
|
||||
(4 for sparse) to record the real and imaginary
|
||||
parts, and also "_ArrayIsComplex_":1 is added.
|
||||
opt.ParseLogical [1|0]: if this is set to 1, logical array elem
|
||||
will use true/false rather than 1/0.
|
||||
opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
|
||||
numerical element will be shown without a square
|
||||
bracket, unless it is the root object; if 0, square
|
||||
brackets are forced for any numerical arrays.
|
||||
opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
|
||||
will use the name of the passed obj variable as the
|
||||
root object name; if obj is an expression and
|
||||
does not have a name, 'root' will be used; if this
|
||||
is set to 0 and rootname is empty, the root level
|
||||
will be merged down to the lower level.
|
||||
opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
|
||||
for example, if opt.JSON='foo', the JSON data is
|
||||
wrapped inside a function call as 'foo(...);'
|
||||
opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
|
||||
back to the string form
|
||||
opt can be replaced by a list of ('param',value) pairs. The param
|
||||
string is equivallent to a field in opt.
|
||||
output:
|
||||
json: a string in the JSON format (see http://json.org)
|
||||
|
||||
examples:
|
||||
a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
|
||||
'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
|
||||
saveubjson('mesh',a)
|
||||
saveubjson('mesh',a,'meshdata.ubj')
|
||||
</pre>
|
||||
|
||||
|
||||
=== examples ===
|
||||
|
||||
Under the "examples" folder, you can find several scripts to demonstrate the
|
||||
basic utilities of JSONlab. Running the "demo_jsonlab_basic.m" script, you
|
||||
will see the conversions from MATLAB data structure to JSON text and backward.
|
||||
In "jsonlab_selftest.m", we load complex JSON files downloaded from the Internet
|
||||
and validate the loadjson/savejson functions for regression testing purposes.
|
||||
Similarly, a "demo_ubjson_basic.m" script is provided to test the saveubjson
|
||||
and loadubjson pairs for various matlab data structures.
|
||||
|
||||
Please run these examples and understand how JSONlab works before you use
|
||||
it to process your data.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
IV. Known Issues and TODOs
|
||||
|
||||
JSONlab has several known limitations. We are striving to make it more general
|
||||
and robust. Hopefully in a few future releases, the limitations become less.
|
||||
|
||||
Here are the known issues:
|
||||
|
||||
# 3D or higher dimensional cell/struct-arrays will be converted to 2D arrays;
|
||||
# When processing names containing multi-byte characters, Octave and MATLAB \
|
||||
can give different field-names; you can use feature('DefaultCharacterSet','latin1') \
|
||||
in MATLAB to get consistant results
|
||||
# Can not handle classes.
|
||||
# saveubjson has not yet supported arbitrary data ([H] in the UBJSON specification)
|
||||
# saveubjson now converts a logical array into a uint8 ([U]) array for now
|
||||
# an unofficial N-D array count syntax is implemented in saveubjson. We are \
|
||||
actively communicating with the UBJSON spec maintainer to investigate the \
|
||||
possibility of making it upstream
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
V. Contribution and feedback
|
||||
|
||||
JSONlab is an open-source project. This means you can not only use it and modify
|
||||
it as you wish, but also you can contribute your changes back to JSONlab so
|
||||
that everyone else can enjoy the improvement. For anyone who want to contribute,
|
||||
please download JSONlab source code from it's subversion repository by using the
|
||||
following command:
|
||||
|
||||
svn checkout svn://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab jsonlab
|
||||
|
||||
You can make changes to the files as needed. Once you are satisfied with your
|
||||
changes, and ready to share it with others, please cd the root directory of
|
||||
JSONlab, and type
|
||||
|
||||
svn diff > yourname_featurename.patch
|
||||
|
||||
You then email the .patch file to JSONlab's maintainer, Qianqian Fang, at
|
||||
the email address shown in the beginning of this file. Qianqian will review
|
||||
the changes and commit it to the subversion if they are satisfactory.
|
||||
|
||||
We appreciate any suggestions and feedbacks from you. Please use iso2mesh's
|
||||
mailing list to report any questions you may have with JSONlab:
|
||||
|
||||
http://groups.google.com/group/iso2mesh-users?hl=en&pli=1
|
||||
|
||||
(Subscription to the mailing list is needed in order to post messages).
|
||||
@@ -0,0 +1,11 @@
|
||||
function header = http_createHeader(name,value)
|
||||
%http_createHeader Simple function for creating input header to urlread2
|
||||
%
|
||||
% header = http_createHeader(name,value)
|
||||
%
|
||||
% CODE: header = struct('name',name,'value',value);
|
||||
%
|
||||
% See Also:
|
||||
% urlread2
|
||||
|
||||
header = struct('name',name,'value',value);
|
||||
@@ -0,0 +1,62 @@
|
||||
function [str,header] = http_paramsToString(params,encodeOption)
|
||||
%http_paramsToString Creates string for a POST or GET requests
|
||||
%
|
||||
% [queryString,header] = http_paramsToString(params, *encodeOption)
|
||||
%
|
||||
% INPUTS
|
||||
% =======================================================================
|
||||
% params: cell array of property/value pairs
|
||||
% NOTE: If the input is in a 2 column matrix, then first column
|
||||
% entries are properties and the second column entries are
|
||||
% values, however this is NOT necessary (generally linear)
|
||||
% encodeOption: (default 1)
|
||||
% 1 - the typical URL encoding scheme (Java call)
|
||||
%
|
||||
% OUTPUTS
|
||||
% =======================================================================
|
||||
% queryString: querystring to add onto URL (LACKS "?", see example)
|
||||
% header : the header that should be attached for post requests when
|
||||
% using urlread2
|
||||
%
|
||||
% EXAMPLE:
|
||||
% ==============================================================
|
||||
% params = {'cmd' 'search' 'db' 'pubmed' 'term' 'wtf batman'};
|
||||
% queryString = http_paramsToString(params);
|
||||
% queryString => cmd=search&db=pubmed&term=wtf+batman
|
||||
%
|
||||
% IMPORTANT: This function does not filter parameters, sort them,
|
||||
% or remove empty inputs (if necessary), this must be done before hand
|
||||
|
||||
if ~exist('encodeOption','var')
|
||||
encodeOption = 1;
|
||||
end
|
||||
|
||||
if size(params,2) == 2 && size(params,1) > 1
|
||||
params = params';
|
||||
params = params(:);
|
||||
end
|
||||
|
||||
str = '';
|
||||
for i=1:2:length(params)
|
||||
if (i == 1), separator = ''; else separator = '&'; end
|
||||
switch encodeOption
|
||||
case 1
|
||||
param = urlencode(params{i});
|
||||
value = urlencode(params{i+1});
|
||||
% case 2
|
||||
% param = oauth.percentEncodeString(params{i});
|
||||
% value = oauth.percentEncodeString(params{i+1});
|
||||
% header = http_getContentTypeHeader(1);
|
||||
otherwise
|
||||
error('Case not used')
|
||||
end
|
||||
str = [str separator param '=' value]; %#ok<AGROW>
|
||||
end
|
||||
|
||||
switch encodeOption
|
||||
case 1
|
||||
header = http_createHeader('Content-Type','application/x-www-form-urlencoded');
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,32 @@
|
||||
function val=jsonopt(key,default,varargin)
|
||||
%
|
||||
% val=jsonopt(key,default,optstruct)
|
||||
%
|
||||
% setting options based on a struct. The struct can be produced
|
||||
% by varargin2struct from a list of 'param','value' pairs
|
||||
%
|
||||
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
%
|
||||
% $Id: loadjson.m 371 2012-06-20 12:43:06Z fangq $
|
||||
%
|
||||
% input:
|
||||
% key: a string with which one look up a value from a struct
|
||||
% default: if the key does not exist, return default
|
||||
% optstruct: a struct where each sub-field is a key
|
||||
%
|
||||
% output:
|
||||
% val: if key exists, val=optstruct.key; otherwise val=default
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
val=default;
|
||||
if(nargin<=2) return; end
|
||||
opt=varargin{1};
|
||||
if(isstruct(opt) && isfield(opt,key))
|
||||
val=getfield(opt,key);
|
||||
end
|
||||
|
||||
@@ -0,0 +1,515 @@
|
||||
function data = loadjson(fname,varargin)
|
||||
%
|
||||
% data=loadjson(fname,opt)
|
||||
% or
|
||||
% data=loadjson(fname,'param1',value1,'param2',value2,...)
|
||||
%
|
||||
% parse a JSON (JavaScript Object Notation) file or string
|
||||
%
|
||||
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% date: 2011/09/09
|
||||
% Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
|
||||
% date: 2009/11/02
|
||||
% François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
|
||||
% date: 2009/03/22
|
||||
% Joel Feenstra:
|
||||
% http://www.mathworks.com/matlabcentral/fileexchange/20565
|
||||
% date: 2008/07/03
|
||||
%
|
||||
% $Id: loadjson.m 437 2014-09-15 18:59:36Z fangq $
|
||||
%
|
||||
% input:
|
||||
% fname: input file name, if fname contains "{}" or "[]", fname
|
||||
% will be interpreted as a JSON string
|
||||
% opt: a struct to store parsing options, opt can be replaced by
|
||||
% a list of ('param',value) pairs. The param string is equivallent
|
||||
% to a field in opt.
|
||||
%
|
||||
% output:
|
||||
% dat: a cell array, where {...} blocks are converted into cell arrays,
|
||||
% and [...] are converted to arrays
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
global pos inStr len esc index_esc len_esc isoct arraytoken
|
||||
|
||||
if(regexp(fname,'[\{\}\]\[]','once'))
|
||||
string=fname;
|
||||
elseif(exist(fname,'file'))
|
||||
fid = fopen(fname,'rb');
|
||||
string = fread(fid,inf,'uint8=>char')';
|
||||
fclose(fid);
|
||||
else
|
||||
error('input file does not exist');
|
||||
end
|
||||
|
||||
pos = 1; len = length(string); inStr = string;
|
||||
isoct=exist('OCTAVE_VERSION','builtin');
|
||||
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
|
||||
jstr=regexprep(inStr,'\\\\',' ');
|
||||
escquote=regexp(jstr,'\\"');
|
||||
arraytoken=sort([arraytoken escquote]);
|
||||
|
||||
% String delimiters and escape chars identified to improve speed:
|
||||
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
|
||||
index_esc = 1; len_esc = length(esc);
|
||||
|
||||
opt=varargin2struct(varargin{:});
|
||||
jsoncount=1;
|
||||
while pos <= len
|
||||
switch(next_char)
|
||||
case '{'
|
||||
data{jsoncount} = parse_object(opt);
|
||||
case '['
|
||||
data{jsoncount} = parse_array(opt);
|
||||
otherwise
|
||||
error_pos('Outer level structure must be an object or an array');
|
||||
end
|
||||
jsoncount=jsoncount+1;
|
||||
end % while
|
||||
|
||||
jsoncount=length(data);
|
||||
if(jsoncount==1 && iscell(data))
|
||||
data=data{1};
|
||||
end
|
||||
|
||||
if(~isempty(data))
|
||||
if(isstruct(data)) % data can be a struct array
|
||||
data=jstruct2array(data);
|
||||
elseif(iscell(data))
|
||||
data=jcell2array(data);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%%
|
||||
function newdata=jcell2array(data)
|
||||
len=length(data);
|
||||
newdata=data;
|
||||
for i=1:len
|
||||
if(isstruct(data{i}))
|
||||
newdata{i}=jstruct2array(data{i});
|
||||
elseif(iscell(data{i}))
|
||||
newdata{i}=jcell2array(data{i});
|
||||
end
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function newdata=jstruct2array(data)
|
||||
fn=fieldnames(data);
|
||||
newdata=data;
|
||||
len=length(data);
|
||||
for i=1:length(fn) % depth-first
|
||||
for j=1:len
|
||||
if(isstruct(getfield(data(j),fn{i})))
|
||||
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
|
||||
end
|
||||
end
|
||||
end
|
||||
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
|
||||
newdata=cell(len,1);
|
||||
for j=1:len
|
||||
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
|
||||
iscpx=0;
|
||||
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
|
||||
if(data(j).x0x5F_ArrayIsComplex_)
|
||||
iscpx=1;
|
||||
end
|
||||
end
|
||||
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
|
||||
if(data(j).x0x5F_ArrayIsSparse_)
|
||||
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
|
||||
dim=data(j).x0x5F_ArraySize_;
|
||||
if(iscpx && size(ndata,2)==4-any(dim==1))
|
||||
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
|
||||
end
|
||||
if isempty(ndata)
|
||||
% All-zeros sparse
|
||||
ndata=sparse(dim(1),prod(dim(2:end)));
|
||||
elseif dim(1)==1
|
||||
% Sparse row vector
|
||||
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
|
||||
elseif dim(2)==1
|
||||
% Sparse column vector
|
||||
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
|
||||
else
|
||||
% Generic sparse array.
|
||||
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
|
||||
end
|
||||
else
|
||||
if(iscpx && size(ndata,2)==4)
|
||||
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
|
||||
end
|
||||
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
|
||||
end
|
||||
end
|
||||
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
|
||||
if(iscpx && size(ndata,2)==2)
|
||||
ndata=complex(ndata(:,1),ndata(:,2));
|
||||
end
|
||||
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
|
||||
end
|
||||
newdata{j}=ndata;
|
||||
end
|
||||
if(len==1)
|
||||
newdata=newdata{1};
|
||||
end
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function object = parse_object(varargin)
|
||||
parse_char('{');
|
||||
object = [];
|
||||
if next_char ~= '}'
|
||||
while 1
|
||||
str = parseStr(varargin{:});
|
||||
if isempty(str)
|
||||
error_pos('Name of value at position %d cannot be empty');
|
||||
end
|
||||
parse_char(':');
|
||||
val = parse_value(varargin{:});
|
||||
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
|
||||
if next_char == '}'
|
||||
break;
|
||||
end
|
||||
parse_char(',');
|
||||
end
|
||||
end
|
||||
parse_char('}');
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function object = parse_array(varargin) % JSON array is written in row-major order
|
||||
global pos inStr isoct
|
||||
parse_char('[');
|
||||
object = cell(0, 1);
|
||||
dim2=[];
|
||||
if next_char ~= ']'
|
||||
[endpos, e1l, e1r, maxlevel]=matching_bracket(inStr,pos);
|
||||
arraystr=['[' inStr(pos:endpos)];
|
||||
arraystr=regexprep(arraystr,'"_NaN_"','NaN');
|
||||
arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
|
||||
arraystr(arraystr==sprintf('\n'))=[];
|
||||
arraystr(arraystr==sprintf('\r'))=[];
|
||||
%arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
|
||||
if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
|
||||
astr=inStr((e1l+1):(e1r-1));
|
||||
astr=regexprep(astr,'"_NaN_"','NaN');
|
||||
astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
|
||||
astr(astr==sprintf('\n'))=[];
|
||||
astr(astr==sprintf('\r'))=[];
|
||||
astr(astr==' ')='';
|
||||
if(isempty(find(astr=='[', 1))) % array is 2D
|
||||
dim2=length(sscanf(astr,'%f,',[1 inf]));
|
||||
end
|
||||
else % array is 1D
|
||||
astr=arraystr(2:end-1);
|
||||
astr(astr==' ')='';
|
||||
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',[1,inf]);
|
||||
if(nextidx>=length(astr)-1)
|
||||
object=obj;
|
||||
pos=endpos;
|
||||
parse_char(']');
|
||||
return;
|
||||
end
|
||||
end
|
||||
if(~isempty(dim2))
|
||||
astr=arraystr;
|
||||
astr(astr=='[')='';
|
||||
astr(astr==']')='';
|
||||
astr(astr==' ')='';
|
||||
[obj, count, errmsg, nextidx]=sscanf(astr,'%f,',inf);
|
||||
if(nextidx>=length(astr)-1)
|
||||
object=reshape(obj,dim2,numel(obj)/dim2)';
|
||||
pos=endpos;
|
||||
parse_char(']');
|
||||
return;
|
||||
end
|
||||
end
|
||||
arraystr=regexprep(arraystr,'\]\s*,','];');
|
||||
try
|
||||
if(isoct && regexp(arraystr,'"','once'))
|
||||
error('Octave eval can produce empty cells for JSON-like input');
|
||||
end
|
||||
object=eval(arraystr);
|
||||
pos=endpos;
|
||||
catch
|
||||
while 1
|
||||
val = parse_value(varargin{:});
|
||||
object{end+1} = val;
|
||||
if next_char == ']'
|
||||
break;
|
||||
end
|
||||
parse_char(',');
|
||||
end
|
||||
end
|
||||
end
|
||||
if(jsonopt('SimplifyCell',0,varargin{:})==1)
|
||||
try
|
||||
oldobj=object;
|
||||
object=cell2mat(object')';
|
||||
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
|
||||
object=oldobj;
|
||||
elseif(size(object,1)>1 && ndims(object)==2)
|
||||
object=object';
|
||||
end
|
||||
catch
|
||||
end
|
||||
end
|
||||
parse_char(']');
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function parse_char(c)
|
||||
global pos inStr len
|
||||
skip_whitespace;
|
||||
if pos > len || inStr(pos) ~= c
|
||||
error_pos(sprintf('Expected %c at position %%d', c));
|
||||
else
|
||||
pos = pos + 1;
|
||||
skip_whitespace;
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function c = next_char
|
||||
global pos inStr len
|
||||
skip_whitespace;
|
||||
if pos > len
|
||||
c = [];
|
||||
else
|
||||
c = inStr(pos);
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function skip_whitespace
|
||||
global pos inStr len
|
||||
while pos <= len && isspace(inStr(pos))
|
||||
pos = pos + 1;
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function str = parseStr(varargin)
|
||||
global pos inStr len esc index_esc len_esc
|
||||
% len, ns = length(inStr), keyboard
|
||||
if inStr(pos) ~= '"'
|
||||
error_pos('String starting with " expected at position %d');
|
||||
else
|
||||
pos = pos + 1;
|
||||
end
|
||||
str = '';
|
||||
while pos <= len
|
||||
while index_esc <= len_esc && esc(index_esc) < pos
|
||||
index_esc = index_esc + 1;
|
||||
end
|
||||
if index_esc > len_esc
|
||||
str = [str inStr(pos:len)];
|
||||
pos = len + 1;
|
||||
break;
|
||||
else
|
||||
str = [str inStr(pos:esc(index_esc)-1)];
|
||||
pos = esc(index_esc);
|
||||
end
|
||||
nstr = length(str); switch inStr(pos)
|
||||
case '"'
|
||||
pos = pos + 1;
|
||||
if(~isempty(str))
|
||||
if(strcmp(str,'_Inf_'))
|
||||
str=Inf;
|
||||
elseif(strcmp(str,'-_Inf_'))
|
||||
str=-Inf;
|
||||
elseif(strcmp(str,'_NaN_'))
|
||||
str=NaN;
|
||||
end
|
||||
end
|
||||
return;
|
||||
case '\'
|
||||
if pos+1 > len
|
||||
error_pos('End of file reached right after escape character');
|
||||
end
|
||||
pos = pos + 1;
|
||||
switch inStr(pos)
|
||||
case {'"' '\' '/'}
|
||||
str(nstr+1) = inStr(pos);
|
||||
pos = pos + 1;
|
||||
case {'b' 'f' 'n' 'r' 't'}
|
||||
str(nstr+1) = sprintf(['\' inStr(pos)]);
|
||||
pos = pos + 1;
|
||||
case 'u'
|
||||
if pos+4 > len
|
||||
error_pos('End of file reached in escaped unicode character');
|
||||
end
|
||||
str(nstr+(1:6)) = inStr(pos-1:pos+4);
|
||||
pos = pos + 5;
|
||||
end
|
||||
otherwise % should never happen
|
||||
str(nstr+1) = inStr(pos), keyboard
|
||||
pos = pos + 1;
|
||||
end
|
||||
end
|
||||
error_pos('End of file while expecting end of inStr');
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function num = parse_number(varargin)
|
||||
global pos inStr len isoct
|
||||
currstr=inStr(pos:end);
|
||||
numstr=0;
|
||||
if(isoct~=0)
|
||||
numstr=regexp(currstr,'^\s*-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?','end');
|
||||
[num, one] = sscanf(currstr, '%f', 1);
|
||||
delta=numstr+1;
|
||||
else
|
||||
[num, one, err, delta] = sscanf(currstr, '%f', 1);
|
||||
if ~isempty(err)
|
||||
error_pos('Error reading number at position %d');
|
||||
end
|
||||
end
|
||||
pos = pos + delta-1;
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function val = parse_value(varargin)
|
||||
global pos inStr len
|
||||
true = 1; false = 0;
|
||||
|
||||
switch(inStr(pos))
|
||||
case '"'
|
||||
val = parseStr(varargin{:});
|
||||
return;
|
||||
case '['
|
||||
val = parse_array(varargin{:});
|
||||
return;
|
||||
case '{'
|
||||
val = parse_object(varargin{:});
|
||||
if isstruct(val)
|
||||
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
|
||||
val=jstruct2array(val);
|
||||
end
|
||||
elseif isempty(val)
|
||||
val = struct;
|
||||
end
|
||||
return;
|
||||
case {'-','0','1','2','3','4','5','6','7','8','9'}
|
||||
val = parse_number(varargin{:});
|
||||
return;
|
||||
case 't'
|
||||
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'true')
|
||||
val = true;
|
||||
pos = pos + 4;
|
||||
return;
|
||||
end
|
||||
case 'f'
|
||||
if pos+4 <= len && strcmpi(inStr(pos:pos+4), 'false')
|
||||
val = false;
|
||||
pos = pos + 5;
|
||||
return;
|
||||
end
|
||||
case 'n'
|
||||
if pos+3 <= len && strcmpi(inStr(pos:pos+3), 'null')
|
||||
val = [];
|
||||
pos = pos + 4;
|
||||
return;
|
||||
end
|
||||
end
|
||||
error_pos('Value expected at position %d');
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function error_pos(msg)
|
||||
global pos inStr len
|
||||
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
|
||||
if poShow(3) == poShow(2)
|
||||
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
|
||||
end
|
||||
msg = [sprintf(msg, pos) ': ' ...
|
||||
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
|
||||
error( ['JSONparser:invalidFormat: ' msg] );
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function str = valid_field(str)
|
||||
global isoct
|
||||
% From MATLAB doc: field names must begin with a letter, which may be
|
||||
% followed by any combination of letters, digits, and underscores.
|
||||
% Invalid characters will be converted to underscores, and the prefix
|
||||
% "x0x[Hex code]_" will be added if the first character is not a letter.
|
||||
pos=regexp(str,'^[^A-Za-z]','once');
|
||||
if(~isempty(pos))
|
||||
if(~isoct)
|
||||
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
|
||||
else
|
||||
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
|
||||
end
|
||||
end
|
||||
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
|
||||
if(~isoct)
|
||||
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
|
||||
else
|
||||
pos=regexp(str,'[^0-9A-Za-z_]');
|
||||
if(isempty(pos)) return; end
|
||||
str0=str;
|
||||
pos0=[0 pos(:)' length(str)];
|
||||
str='';
|
||||
for i=1:length(pos)
|
||||
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
|
||||
end
|
||||
if(pos(end)~=length(str))
|
||||
str=[str str0(pos0(end-1)+1:pos0(end))];
|
||||
end
|
||||
end
|
||||
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function endpos = matching_quote(str,pos)
|
||||
len=length(str);
|
||||
while(pos<len)
|
||||
if(str(pos)=='"')
|
||||
if(~(pos>1 && str(pos-1)=='\'))
|
||||
endpos=pos;
|
||||
return;
|
||||
end
|
||||
end
|
||||
pos=pos+1;
|
||||
end
|
||||
error('unmatched quotation mark');
|
||||
%%-------------------------------------------------------------------------
|
||||
function [endpos, e1l, e1r, maxlevel] = matching_bracket(str,pos)
|
||||
global arraytoken
|
||||
level=1;
|
||||
maxlevel=level;
|
||||
endpos=0;
|
||||
bpos=arraytoken(arraytoken>=pos);
|
||||
tokens=str(bpos);
|
||||
len=length(tokens);
|
||||
pos=1;
|
||||
e1l=[];
|
||||
e1r=[];
|
||||
while(pos<=len)
|
||||
c=tokens(pos);
|
||||
if(c==']')
|
||||
level=level-1;
|
||||
if(isempty(e1r)) e1r=bpos(pos); end
|
||||
if(level==0)
|
||||
endpos=bpos(pos);
|
||||
return
|
||||
end
|
||||
end
|
||||
if(c=='[')
|
||||
if(isempty(e1l)) e1l=bpos(pos); end
|
||||
level=level+1;
|
||||
maxlevel=max(maxlevel,level);
|
||||
end
|
||||
if(c=='"')
|
||||
pos=matching_quote(tokens,pos+1);
|
||||
end
|
||||
pos=pos+1;
|
||||
end
|
||||
if(endpos==0)
|
||||
error('unmatched "]"');
|
||||
end
|
||||
|
||||
@@ -0,0 +1,512 @@
|
||||
function data = loadubjson(fname,varargin)
|
||||
%
|
||||
% data=loadubjson(fname,opt)
|
||||
% or
|
||||
% data=loadubjson(fname,'param1',value1,'param2',value2,...)
|
||||
%
|
||||
% parse a JSON (JavaScript Object Notation) file or string
|
||||
%
|
||||
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% date: 2013/08/01
|
||||
%
|
||||
% $Id: loadubjson.m 436 2014-08-05 20:51:40Z fangq $
|
||||
%
|
||||
% input:
|
||||
% fname: input file name, if fname contains "{}" or "[]", fname
|
||||
% will be interpreted as a UBJSON string
|
||||
% opt: a struct to store parsing options, opt can be replaced by
|
||||
% a list of ('param',value) pairs. The param string is equivallent
|
||||
% to a field in opt.
|
||||
%
|
||||
% output:
|
||||
% dat: a cell array, where {...} blocks are converted into cell arrays,
|
||||
% and [...] are converted to arrays
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
global pos inStr len esc index_esc len_esc isoct arraytoken fileendian systemendian
|
||||
|
||||
if(regexp(fname,'[\{\}\]\[]','once'))
|
||||
string=fname;
|
||||
elseif(exist(fname,'file'))
|
||||
fid = fopen(fname,'rb');
|
||||
string = fread(fid,inf,'uint8=>char')';
|
||||
fclose(fid);
|
||||
else
|
||||
error('input file does not exist');
|
||||
end
|
||||
|
||||
pos = 1; len = length(string); inStr = string;
|
||||
isoct=exist('OCTAVE_VERSION','builtin');
|
||||
arraytoken=find(inStr=='[' | inStr==']' | inStr=='"');
|
||||
jstr=regexprep(inStr,'\\\\',' ');
|
||||
escquote=regexp(jstr,'\\"');
|
||||
arraytoken=sort([arraytoken escquote]);
|
||||
|
||||
% String delimiters and escape chars identified to improve speed:
|
||||
esc = find(inStr=='"' | inStr=='\' ); % comparable to: regexp(inStr, '["\\]');
|
||||
index_esc = 1; len_esc = length(esc);
|
||||
|
||||
opt=varargin2struct(varargin{:});
|
||||
fileendian=upper(jsonopt('IntEndian','B',opt));
|
||||
[os,maxelem,systemendian]=computer;
|
||||
|
||||
jsoncount=1;
|
||||
while pos <= len
|
||||
switch(next_char)
|
||||
case '{'
|
||||
data{jsoncount} = parse_object(opt);
|
||||
case '['
|
||||
data{jsoncount} = parse_array(opt);
|
||||
otherwise
|
||||
error_pos('Outer level structure must be an object or an array');
|
||||
end
|
||||
jsoncount=jsoncount+1;
|
||||
end % while
|
||||
|
||||
jsoncount=length(data);
|
||||
if(jsoncount==1 && iscell(data))
|
||||
data=data{1};
|
||||
end
|
||||
|
||||
if(~isempty(data))
|
||||
if(isstruct(data)) % data can be a struct array
|
||||
data=jstruct2array(data);
|
||||
elseif(iscell(data))
|
||||
data=jcell2array(data);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%%
|
||||
function newdata=parse_collection(id,data,obj)
|
||||
|
||||
if(jsoncount>0 && exist('data','var'))
|
||||
if(~iscell(data))
|
||||
newdata=cell(1);
|
||||
newdata{1}=data;
|
||||
data=newdata;
|
||||
end
|
||||
end
|
||||
|
||||
%%
|
||||
function newdata=jcell2array(data)
|
||||
len=length(data);
|
||||
newdata=data;
|
||||
for i=1:len
|
||||
if(isstruct(data{i}))
|
||||
newdata{i}=jstruct2array(data{i});
|
||||
elseif(iscell(data{i}))
|
||||
newdata{i}=jcell2array(data{i});
|
||||
end
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function newdata=jstruct2array(data)
|
||||
fn=fieldnames(data);
|
||||
newdata=data;
|
||||
len=length(data);
|
||||
for i=1:length(fn) % depth-first
|
||||
for j=1:len
|
||||
if(isstruct(getfield(data(j),fn{i})))
|
||||
newdata(j)=setfield(newdata(j),fn{i},jstruct2array(getfield(data(j),fn{i})));
|
||||
end
|
||||
end
|
||||
end
|
||||
if(~isempty(strmatch('x0x5F_ArrayType_',fn)) && ~isempty(strmatch('x0x5F_ArrayData_',fn)))
|
||||
newdata=cell(len,1);
|
||||
for j=1:len
|
||||
ndata=cast(data(j).x0x5F_ArrayData_,data(j).x0x5F_ArrayType_);
|
||||
iscpx=0;
|
||||
if(~isempty(strmatch('x0x5F_ArrayIsComplex_',fn)))
|
||||
if(data(j).x0x5F_ArrayIsComplex_)
|
||||
iscpx=1;
|
||||
end
|
||||
end
|
||||
if(~isempty(strmatch('x0x5F_ArrayIsSparse_',fn)))
|
||||
if(data(j).x0x5F_ArrayIsSparse_)
|
||||
if(~isempty(strmatch('x0x5F_ArraySize_',fn)))
|
||||
dim=double(data(j).x0x5F_ArraySize_);
|
||||
if(iscpx && size(ndata,2)==4-any(dim==1))
|
||||
ndata(:,end-1)=complex(ndata(:,end-1),ndata(:,end));
|
||||
end
|
||||
if isempty(ndata)
|
||||
% All-zeros sparse
|
||||
ndata=sparse(dim(1),prod(dim(2:end)));
|
||||
elseif dim(1)==1
|
||||
% Sparse row vector
|
||||
ndata=sparse(1,ndata(:,1),ndata(:,2),dim(1),prod(dim(2:end)));
|
||||
elseif dim(2)==1
|
||||
% Sparse column vector
|
||||
ndata=sparse(ndata(:,1),1,ndata(:,2),dim(1),prod(dim(2:end)));
|
||||
else
|
||||
% Generic sparse array.
|
||||
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3),dim(1),prod(dim(2:end)));
|
||||
end
|
||||
else
|
||||
if(iscpx && size(ndata,2)==4)
|
||||
ndata(:,3)=complex(ndata(:,3),ndata(:,4));
|
||||
end
|
||||
ndata=sparse(ndata(:,1),ndata(:,2),ndata(:,3));
|
||||
end
|
||||
end
|
||||
elseif(~isempty(strmatch('x0x5F_ArraySize_',fn)))
|
||||
if(iscpx && size(ndata,2)==2)
|
||||
ndata=complex(ndata(:,1),ndata(:,2));
|
||||
end
|
||||
ndata=reshape(ndata(:),data(j).x0x5F_ArraySize_);
|
||||
end
|
||||
newdata{j}=ndata;
|
||||
end
|
||||
if(len==1)
|
||||
newdata=newdata{1};
|
||||
end
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function object = parse_object(varargin)
|
||||
parse_char('{');
|
||||
object = [];
|
||||
type='';
|
||||
count=-1;
|
||||
if(next_char == '$')
|
||||
type=inStr(pos+1); % TODO
|
||||
pos=pos+2;
|
||||
end
|
||||
if(next_char == '#')
|
||||
pos=pos+1;
|
||||
count=double(parse_number());
|
||||
end
|
||||
if next_char ~= '}'
|
||||
num=0;
|
||||
while 1
|
||||
str = parseStr(varargin{:});
|
||||
if isempty(str)
|
||||
error_pos('Name of value at position %d cannot be empty');
|
||||
end
|
||||
%parse_char(':');
|
||||
val = parse_value(varargin{:});
|
||||
num=num+1;
|
||||
eval( sprintf( 'object.%s = val;', valid_field(str) ) );
|
||||
if next_char == '}' || (count>=0 && num>=count)
|
||||
break;
|
||||
end
|
||||
%parse_char(',');
|
||||
end
|
||||
end
|
||||
if(count==-1)
|
||||
parse_char('}');
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function [cid,len]=elem_info(type)
|
||||
id=strfind('iUIlLdD',type);
|
||||
dataclass={'int8','uint8','int16','int32','int64','single','double'};
|
||||
bytelen=[1,1,2,4,8,4,8];
|
||||
if(id>0)
|
||||
cid=dataclass{id};
|
||||
len=bytelen(id);
|
||||
else
|
||||
error_pos('unsupported type at position %d');
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
|
||||
function [data adv]=parse_block(type,count,varargin)
|
||||
global pos inStr isoct fileendian systemendian
|
||||
[cid,len]=elem_info(type);
|
||||
datastr=inStr(pos:pos+len*count-1);
|
||||
if(isoct)
|
||||
newdata=int8(datastr);
|
||||
else
|
||||
newdata=uint8(datastr);
|
||||
end
|
||||
id=strfind('iUIlLdD',type);
|
||||
if(id<=5 && fileendian~=systemendian)
|
||||
newdata=swapbytes(typecast(newdata,cid));
|
||||
end
|
||||
data=typecast(newdata,cid);
|
||||
adv=double(len*count);
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
|
||||
function object = parse_array(varargin) % JSON array is written in row-major order
|
||||
global pos inStr isoct
|
||||
parse_char('[');
|
||||
object = cell(0, 1);
|
||||
dim=[];
|
||||
type='';
|
||||
count=-1;
|
||||
if(next_char == '$')
|
||||
type=inStr(pos+1);
|
||||
pos=pos+2;
|
||||
end
|
||||
if(next_char == '#')
|
||||
pos=pos+1;
|
||||
if(next_char=='[')
|
||||
dim=parse_array(varargin{:});
|
||||
count=prod(double(dim));
|
||||
else
|
||||
count=double(parse_number());
|
||||
end
|
||||
end
|
||||
if(~isempty(type))
|
||||
if(count>=0)
|
||||
[object adv]=parse_block(type,count,varargin{:});
|
||||
if(~isempty(dim))
|
||||
object=reshape(object,dim);
|
||||
end
|
||||
pos=pos+adv;
|
||||
return;
|
||||
else
|
||||
endpos=matching_bracket(inStr,pos);
|
||||
[cid,len]=elem_info(type);
|
||||
count=(endpos-pos)/len;
|
||||
[object adv]=parse_block(type,count,varargin{:});
|
||||
pos=pos+adv;
|
||||
parse_char(']');
|
||||
return;
|
||||
end
|
||||
end
|
||||
if next_char ~= ']'
|
||||
while 1
|
||||
val = parse_value(varargin{:});
|
||||
object{end+1} = val;
|
||||
if next_char == ']'
|
||||
break;
|
||||
end
|
||||
%parse_char(',');
|
||||
end
|
||||
end
|
||||
if(jsonopt('SimplifyCell',0,varargin{:})==1)
|
||||
try
|
||||
oldobj=object;
|
||||
object=cell2mat(object')';
|
||||
if(iscell(oldobj) && isstruct(object) && numel(object)>1 && jsonopt('SimplifyCellArray',1,varargin{:})==0)
|
||||
object=oldobj;
|
||||
elseif(size(object,1)>1 && ndims(object)==2)
|
||||
object=object';
|
||||
end
|
||||
catch
|
||||
end
|
||||
end
|
||||
if(count==-1)
|
||||
parse_char(']');
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function parse_char(c)
|
||||
global pos inStr len
|
||||
skip_whitespace;
|
||||
if pos > len || inStr(pos) ~= c
|
||||
error_pos(sprintf('Expected %c at position %%d', c));
|
||||
else
|
||||
pos = pos + 1;
|
||||
skip_whitespace;
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function c = next_char
|
||||
global pos inStr len
|
||||
skip_whitespace;
|
||||
if pos > len
|
||||
c = [];
|
||||
else
|
||||
c = inStr(pos);
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function skip_whitespace
|
||||
global pos inStr len
|
||||
while pos <= len && isspace(inStr(pos))
|
||||
pos = pos + 1;
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function str = parseStr(varargin)
|
||||
global pos inStr esc index_esc len_esc
|
||||
% len, ns = length(inStr), keyboard
|
||||
type=inStr(pos);
|
||||
if type ~= 'S' && type ~= 'C' && type ~= 'H'
|
||||
error_pos('String starting with S expected at position %d');
|
||||
else
|
||||
pos = pos + 1;
|
||||
end
|
||||
if(type == 'C')
|
||||
str=inStr(pos);
|
||||
pos=pos+1;
|
||||
return;
|
||||
end
|
||||
bytelen=double(parse_number());
|
||||
if(length(inStr)>=pos+bytelen-1)
|
||||
str=inStr(pos:pos+bytelen-1);
|
||||
pos=pos+bytelen;
|
||||
else
|
||||
error_pos('End of file while expecting end of inStr');
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function num = parse_number(varargin)
|
||||
global pos inStr len isoct fileendian systemendian
|
||||
id=strfind('iUIlLdD',inStr(pos));
|
||||
if(isempty(id))
|
||||
error_pos('expecting a number at position %d');
|
||||
end
|
||||
type={'int8','uint8','int16','int32','int64','single','double'};
|
||||
bytelen=[1,1,2,4,8,4,8];
|
||||
datastr=inStr(pos+1:pos+bytelen(id));
|
||||
if(isoct)
|
||||
newdata=int8(datastr);
|
||||
else
|
||||
newdata=uint8(datastr);
|
||||
end
|
||||
if(id<=5 && fileendian~=systemendian)
|
||||
newdata=swapbytes(typecast(newdata,type{id}));
|
||||
end
|
||||
num=typecast(newdata,type{id});
|
||||
pos = pos + bytelen(id)+1;
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function val = parse_value(varargin)
|
||||
global pos inStr len
|
||||
true = 1; false = 0;
|
||||
|
||||
switch(inStr(pos))
|
||||
case {'S','C','H'}
|
||||
val = parseStr(varargin{:});
|
||||
return;
|
||||
case '['
|
||||
val = parse_array(varargin{:});
|
||||
return;
|
||||
case '{'
|
||||
val = parse_object(varargin{:});
|
||||
if isstruct(val)
|
||||
if(~isempty(strmatch('x0x5F_ArrayType_',fieldnames(val), 'exact')))
|
||||
val=jstruct2array(val);
|
||||
end
|
||||
elseif isempty(val)
|
||||
val = struct;
|
||||
end
|
||||
return;
|
||||
case {'i','U','I','l','L','d','D'}
|
||||
val = parse_number(varargin{:});
|
||||
return;
|
||||
case 'T'
|
||||
val = true;
|
||||
pos = pos + 1;
|
||||
return;
|
||||
case 'F'
|
||||
val = false;
|
||||
pos = pos + 1;
|
||||
return;
|
||||
case {'Z','N'}
|
||||
val = [];
|
||||
pos = pos + 1;
|
||||
return;
|
||||
end
|
||||
error_pos('Value expected at position %d');
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function error_pos(msg)
|
||||
global pos inStr len
|
||||
poShow = max(min([pos-15 pos-1 pos pos+20],len),1);
|
||||
if poShow(3) == poShow(2)
|
||||
poShow(3:4) = poShow(2)+[0 -1]; % display nothing after
|
||||
end
|
||||
msg = [sprintf(msg, pos) ': ' ...
|
||||
inStr(poShow(1):poShow(2)) '<error>' inStr(poShow(3):poShow(4)) ];
|
||||
error( ['JSONparser:invalidFormat: ' msg] );
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
|
||||
function str = valid_field(str)
|
||||
global isoct
|
||||
% From MATLAB doc: field names must begin with a letter, which may be
|
||||
% followed by any combination of letters, digits, and underscores.
|
||||
% Invalid characters will be converted to underscores, and the prefix
|
||||
% "x0x[Hex code]_" will be added if the first character is not a letter.
|
||||
pos=regexp(str,'^[^A-Za-z]','once');
|
||||
if(~isempty(pos))
|
||||
if(~isoct)
|
||||
str=regexprep(str,'^([^A-Za-z])','x0x${sprintf(''%X'',unicode2native($1))}_','once');
|
||||
else
|
||||
str=sprintf('x0x%X_%s',char(str(1)),str(2:end));
|
||||
end
|
||||
end
|
||||
if(isempty(regexp(str,'[^0-9A-Za-z_]', 'once' ))) return; end
|
||||
if(~isoct)
|
||||
str=regexprep(str,'([^0-9A-Za-z_])','_0x${sprintf(''%X'',unicode2native($1))}_');
|
||||
else
|
||||
pos=regexp(str,'[^0-9A-Za-z_]');
|
||||
if(isempty(pos)) return; end
|
||||
str0=str;
|
||||
pos0=[0 pos(:)' length(str)];
|
||||
str='';
|
||||
for i=1:length(pos)
|
||||
str=[str str0(pos0(i)+1:pos(i)-1) sprintf('_0x%X_',str0(pos(i)))];
|
||||
end
|
||||
if(pos(end)~=length(str))
|
||||
str=[str str0(pos0(end-1)+1:pos0(end))];
|
||||
end
|
||||
end
|
||||
%str(~isletter(str) & ~('0' <= str & str <= '9')) = '_';
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function endpos = matching_quote(str,pos)
|
||||
len=length(str);
|
||||
while(pos<len)
|
||||
if(str(pos)=='"')
|
||||
if(~(pos>1 && str(pos-1)=='\'))
|
||||
endpos=pos;
|
||||
return;
|
||||
end
|
||||
end
|
||||
pos=pos+1;
|
||||
end
|
||||
error('unmatched quotation mark');
|
||||
%%-------------------------------------------------------------------------
|
||||
function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
|
||||
global arraytoken
|
||||
level=1;
|
||||
maxlevel=level;
|
||||
endpos=0;
|
||||
bpos=arraytoken(arraytoken>=pos);
|
||||
tokens=str(bpos);
|
||||
len=length(tokens);
|
||||
pos=1;
|
||||
e1l=[];
|
||||
e1r=[];
|
||||
while(pos<=len)
|
||||
c=tokens(pos);
|
||||
if(c==']')
|
||||
level=level-1;
|
||||
if(isempty(e1r)) e1r=bpos(pos); end
|
||||
if(level==0)
|
||||
endpos=bpos(pos);
|
||||
return
|
||||
end
|
||||
end
|
||||
if(c=='[')
|
||||
if(isempty(e1l)) e1l=bpos(pos); end
|
||||
level=level+1;
|
||||
maxlevel=max(maxlevel,level);
|
||||
end
|
||||
if(c=='"')
|
||||
pos=matching_quote(tokens,pos+1);
|
||||
end
|
||||
pos=pos+1;
|
||||
end
|
||||
if(endpos==0)
|
||||
error('unmatched "]"');
|
||||
end
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
function s=mergestruct(s1,s2)
|
||||
%
|
||||
% s=mergestruct(s1,s2)
|
||||
%
|
||||
% merge two struct objects into one
|
||||
%
|
||||
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% date: 2012/12/22
|
||||
%
|
||||
% input:
|
||||
% s1,s2: a struct object, s1 and s2 can not be arrays
|
||||
%
|
||||
% output:
|
||||
% s: the merged struct object. fields in s1 and s2 will be combined in s.
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
if(~isstruct(s1) || ~isstruct(s2))
|
||||
error('input parameters contain non-struct');
|
||||
end
|
||||
if(length(s1)>1 || length(s2)>1)
|
||||
error('can not merge struct arrays');
|
||||
end
|
||||
fn=fieldnames(s2);
|
||||
s=s1;
|
||||
for i=1:length(fn)
|
||||
s=setfield(s,fn{i},getfield(s2,fn{i}));
|
||||
end
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
function json=savejson(rootname,obj,varargin)
|
||||
%
|
||||
% json=savejson(rootname,obj,filename)
|
||||
% or
|
||||
% json=savejson(rootname,obj,opt)
|
||||
% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
|
||||
%
|
||||
% convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
|
||||
% Object Notation) string
|
||||
%
|
||||
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% created on 2011/09/09
|
||||
%
|
||||
% $Id: savejson.m 439 2014-09-17 05:31:08Z fangq $
|
||||
%
|
||||
% input:
|
||||
% rootname: name of the root-object, if set to '', will use variable name
|
||||
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
|
||||
% filename: a string for the file name to save the output JSON data
|
||||
% opt: a struct for additional options, use [] if all use default
|
||||
% opt can have the following fields (first in [.|.] is the default)
|
||||
%
|
||||
% opt.FileName [''|string]: a file name to save the output JSON data
|
||||
% opt.FloatFormat ['%.10g'|string]: format to show each numeric element
|
||||
% of a 1D/2D array;
|
||||
% opt.ArrayIndent [1|0]: if 1, output explicit data array with
|
||||
% precedent indentation; if 0, no indentation
|
||||
% opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
|
||||
% array in JSON array format; if sets to 1, an
|
||||
% array will be shown as a struct with fields
|
||||
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
|
||||
% sparse arrays, the non-zero elements will be
|
||||
% saved to _ArrayData_ field in triplet-format i.e.
|
||||
% (ix,iy,val) and "_ArrayIsSparse_" will be added
|
||||
% with a value of 1; for a complex array, the
|
||||
% _ArrayData_ array will include two columns
|
||||
% (4 for sparse) to record the real and imaginary
|
||||
% parts, and also "_ArrayIsComplex_":1 is added.
|
||||
% opt.ParseLogical [0|1]: if this is set to 1, logical array elem
|
||||
% will use true/false rather than 1/0.
|
||||
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
|
||||
% numerical element will be shown without a square
|
||||
% bracket, unless it is the root object; if 0, square
|
||||
% brackets are forced for any numerical arrays.
|
||||
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, savejson
|
||||
% will use the name of the passed obj variable as the
|
||||
% root object name; if obj is an expression and
|
||||
% does not have a name, 'root' will be used; if this
|
||||
% is set to 0 and rootname is empty, the root level
|
||||
% will be merged down to the lower level.
|
||||
% opt.Inf ['"$1_Inf_"'|string]: a customized regular expression pattern
|
||||
% to represent +/-Inf. The matched pattern is '([-+]*)Inf'
|
||||
% and $1 represents the sign. For those who want to use
|
||||
% 1e999 to represent Inf, they can set opt.Inf to '$11e999'
|
||||
% opt.NaN ['"_NaN_"'|string]: a customized regular expression pattern
|
||||
% to represent NaN
|
||||
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
|
||||
% for example, if opt.JSON='foo', the JSON data is
|
||||
% wrapped inside a function call as 'foo(...);'
|
||||
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
|
||||
% back to the string form
|
||||
% opt.SaveBinary [0|1]: 1 - save the JSON file in binary mode; 0 - text mode.
|
||||
% opt can be replaced by a list of ('param',value) pairs. The param
|
||||
% string is equivallent to a field in opt.
|
||||
% output:
|
||||
% json: a string in the JSON format (see http://json.org)
|
||||
%
|
||||
% examples:
|
||||
% a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
|
||||
% 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
|
||||
% savejson('mesh',a)
|
||||
% savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
if(nargin==1)
|
||||
varname=inputname(1);
|
||||
obj=rootname;
|
||||
if(isempty(varname))
|
||||
varname='root';
|
||||
end
|
||||
rootname=varname;
|
||||
else
|
||||
varname=inputname(2);
|
||||
end
|
||||
if(length(varargin)==1 && ischar(varargin{1}))
|
||||
opt=struct('FileName',varargin{1});
|
||||
else
|
||||
opt=varargin2struct(varargin{:});
|
||||
end
|
||||
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
|
||||
rootisarray=0;
|
||||
rootlevel=1;
|
||||
forceroot=jsonopt('ForceRootName',0,opt);
|
||||
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
|
||||
rootisarray=1;
|
||||
rootlevel=0;
|
||||
else
|
||||
if(isempty(rootname))
|
||||
rootname=varname;
|
||||
end
|
||||
end
|
||||
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
|
||||
rootname='root';
|
||||
end
|
||||
json=obj2json(rootname,obj,rootlevel,opt);
|
||||
if(rootisarray)
|
||||
json=sprintf('%s\n',json);
|
||||
else
|
||||
json=sprintf('{\n%s\n}\n',json);
|
||||
end
|
||||
|
||||
jsonp=jsonopt('JSONP','',opt);
|
||||
if(~isempty(jsonp))
|
||||
json=sprintf('%s(%s);\n',jsonp,json);
|
||||
end
|
||||
|
||||
% save to a file if FileName is set, suggested by Patrick Rapin
|
||||
if(~isempty(jsonopt('FileName','',opt)))
|
||||
if(jsonopt('SaveBinary',0,opt)==1)
|
||||
fid = fopen(opt.FileName, 'wb');
|
||||
fwrite(fid,json);
|
||||
else
|
||||
fid = fopen(opt.FileName, 'wt');
|
||||
fwrite(fid,json,'char');
|
||||
end
|
||||
fclose(fid);
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=obj2json(name,item,level,varargin)
|
||||
|
||||
if(iscell(item))
|
||||
txt=cell2json(name,item,level,varargin{:});
|
||||
elseif(isstruct(item))
|
||||
txt=struct2json(name,item,level,varargin{:});
|
||||
elseif(ischar(item))
|
||||
txt=str2json(name,item,level,varargin{:});
|
||||
else
|
||||
txt=mat2json(name,item,level,varargin{:});
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=cell2json(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~iscell(item))
|
||||
error('input is not a cell');
|
||||
end
|
||||
|
||||
dim=size(item);
|
||||
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
|
||||
item=reshape(item,dim(1),numel(item)/dim(1));
|
||||
dim=size(item);
|
||||
end
|
||||
len=numel(item);
|
||||
padding0=repmat(sprintf('\t'),1,level);
|
||||
padding2=repmat(sprintf('\t'),1,level+1);
|
||||
if(len>1)
|
||||
if(~isempty(name))
|
||||
txt=sprintf('%s"%s": [\n',padding0, checkname(name,varargin{:})); name='';
|
||||
else
|
||||
txt=sprintf('%s[\n',padding0);
|
||||
end
|
||||
elseif(len==0)
|
||||
if(~isempty(name))
|
||||
txt=sprintf('%s"%s": []',padding0, checkname(name,varargin{:})); name='';
|
||||
else
|
||||
txt=sprintf('%s[]',padding0);
|
||||
end
|
||||
end
|
||||
for j=1:dim(2)
|
||||
if(dim(1)>1) txt=sprintf('%s%s[\n',txt,padding2); end
|
||||
for i=1:dim(1)
|
||||
txt=sprintf('%s%s',txt,obj2json(name,item{i,j},level+(dim(1)>1)+1,varargin{:}));
|
||||
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
|
||||
end
|
||||
if(dim(1)>1) txt=sprintf('%s\n%s]',txt,padding2); end
|
||||
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
|
||||
%if(j==dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
|
||||
end
|
||||
if(len>1) txt=sprintf('%s\n%s]',txt,padding0); end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=struct2json(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~isstruct(item))
|
||||
error('input is not a struct');
|
||||
end
|
||||
dim=size(item);
|
||||
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
|
||||
item=reshape(item,dim(1),numel(item)/dim(1));
|
||||
dim=size(item);
|
||||
end
|
||||
len=numel(item);
|
||||
padding0=repmat(sprintf('\t'),1,level);
|
||||
padding2=repmat(sprintf('\t'),1,level+1);
|
||||
|
||||
if(~isempty(name))
|
||||
if(len>1) txt=sprintf('%s"%s": [\n',padding0,checkname(name,varargin{:})); end
|
||||
else
|
||||
if(len>1) txt=sprintf('%s[\n',padding0); end
|
||||
end
|
||||
for j=1:dim(2)
|
||||
if(dim(1)>1) txt=sprintf('%s%s[\n',txt,padding2); end
|
||||
for i=1:dim(1)
|
||||
names = fieldnames(item(i,j));
|
||||
if(~isempty(name) && len==1)
|
||||
txt=sprintf('%s%s"%s": {\n',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)), checkname(name,varargin{:}));
|
||||
else
|
||||
txt=sprintf('%s%s{\n',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)));
|
||||
end
|
||||
if(~isempty(names))
|
||||
for e=1:length(names)
|
||||
txt=sprintf('%s%s',txt,obj2json(names{e},getfield(item(i,j),...
|
||||
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:}));
|
||||
if(e<length(names)) txt=sprintf('%s%s',txt,','); end
|
||||
txt=sprintf('%s%s',txt,sprintf('\n'));
|
||||
end
|
||||
end
|
||||
txt=sprintf('%s%s}',txt,repmat(sprintf('\t'),1,level+(dim(1)>1)+(len>1)));
|
||||
if(i<dim(1)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
|
||||
end
|
||||
if(dim(1)>1) txt=sprintf('%s\n%s]',txt,padding2); end
|
||||
if(j<dim(2)) txt=sprintf('%s%s',txt,sprintf(',\n')); end
|
||||
end
|
||||
if(len>1) txt=sprintf('%s\n%s]',txt,padding0); end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=str2json(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~ischar(item))
|
||||
error('input is not a string');
|
||||
end
|
||||
item=reshape(item, max(size(item),[1 0]));
|
||||
len=size(item,1);
|
||||
sep=sprintf(',\n');
|
||||
|
||||
padding1=repmat(sprintf('\t'),1,level);
|
||||
padding0=repmat(sprintf('\t'),1,level+1);
|
||||
|
||||
if(~isempty(name))
|
||||
if(len>1) txt=sprintf('%s"%s": [\n',padding1,checkname(name,varargin{:})); end
|
||||
else
|
||||
if(len>1) txt=sprintf('%s[\n',padding1); end
|
||||
end
|
||||
isoct=jsonopt('IsOctave',0,varargin{:});
|
||||
for e=1:len
|
||||
if(isoct)
|
||||
val=regexprep(item(e,:),'\\','\\');
|
||||
val=regexprep(val,'"','\"');
|
||||
val=regexprep(val,'^"','\"');
|
||||
else
|
||||
val=regexprep(item(e,:),'\\','\\\\');
|
||||
val=regexprep(val,'"','\\"');
|
||||
val=regexprep(val,'^"','\\"');
|
||||
end
|
||||
val=escapejsonstring(val);
|
||||
if(len==1)
|
||||
obj=['"' checkname(name,varargin{:}) '": ' '"',val,'"'];
|
||||
if(isempty(name)) obj=['"',val,'"']; end
|
||||
txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level),obj);
|
||||
else
|
||||
txt=sprintf('%s%s%s%s',txt,repmat(sprintf('\t'),1,level+1),['"',val,'"']);
|
||||
end
|
||||
if(e==len) sep=''; end
|
||||
txt=sprintf('%s%s',txt,sep);
|
||||
end
|
||||
if(len>1) txt=sprintf('%s\n%s%s',txt,padding1,']'); end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=mat2json(name,item,level,varargin)
|
||||
if(~isnumeric(item) && ~islogical(item))
|
||||
error('input is not an array');
|
||||
end
|
||||
|
||||
padding1=repmat(sprintf('\t'),1,level);
|
||||
padding0=repmat(sprintf('\t'),1,level+1);
|
||||
|
||||
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
|
||||
isempty(item) ||jsonopt('ArrayToStruct',0,varargin{:}))
|
||||
if(isempty(name))
|
||||
txt=sprintf('%s{\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',...
|
||||
padding1,padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') );
|
||||
else
|
||||
txt=sprintf('%s"%s": {\n%s"_ArrayType_": "%s",\n%s"_ArraySize_": %s,\n',...
|
||||
padding1,checkname(name,varargin{:}),padding0,class(item),padding0,regexprep(mat2str(size(item)),'\s+',',') );
|
||||
end
|
||||
else
|
||||
if(isempty(name))
|
||||
txt=sprintf('%s%s',padding1,matdata2json(item,level+1,varargin{:}));
|
||||
else
|
||||
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
|
||||
numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
|
||||
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),numtxt);
|
||||
else
|
||||
txt=sprintf('%s"%s": %s',padding1,checkname(name,varargin{:}),matdata2json(item,level+1,varargin{:}));
|
||||
end
|
||||
end
|
||||
return;
|
||||
end
|
||||
dataformat='%s%s%s%s%s';
|
||||
|
||||
if(issparse(item))
|
||||
[ix,iy]=find(item);
|
||||
data=full(item(find(item)));
|
||||
if(~isreal(item))
|
||||
data=[real(data(:)),imag(data(:))];
|
||||
if(size(item,1)==1)
|
||||
% Kludge to have data's 'transposedness' match item's.
|
||||
% (Necessary for complex row vector handling below.)
|
||||
data=data';
|
||||
end
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n'));
|
||||
end
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsSparse_": ','1', sprintf(',\n'));
|
||||
if(size(item,1)==1)
|
||||
% Row vector, store only column indices.
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
|
||||
matdata2json([iy(:),data'],level+2,varargin{:}), sprintf('\n'));
|
||||
elseif(size(item,2)==1)
|
||||
% Column vector, store only row indices.
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
|
||||
matdata2json([ix,data],level+2,varargin{:}), sprintf('\n'));
|
||||
else
|
||||
% General case, store row and column indices.
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
|
||||
matdata2json([ix,iy,data],level+2,varargin{:}), sprintf('\n'));
|
||||
end
|
||||
else
|
||||
if(isreal(item))
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
|
||||
matdata2json(item(:)',level+2,varargin{:}), sprintf('\n'));
|
||||
else
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayIsComplex_": ','1', sprintf(',\n'));
|
||||
txt=sprintf(dataformat,txt,padding0,'"_ArrayData_": ',...
|
||||
matdata2json([real(item(:)) imag(item(:))],level+2,varargin{:}), sprintf('\n'));
|
||||
end
|
||||
end
|
||||
txt=sprintf('%s%s%s',txt,padding1,'}');
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=matdata2json(mat,level,varargin)
|
||||
if(size(mat,1)==1)
|
||||
pre='';
|
||||
post='';
|
||||
level=level-1;
|
||||
else
|
||||
pre=sprintf('[\n');
|
||||
post=sprintf('\n%s]',repmat(sprintf('\t'),1,level-1));
|
||||
end
|
||||
if(isempty(mat))
|
||||
txt='null';
|
||||
return;
|
||||
end
|
||||
floatformat=jsonopt('FloatFormat','%.10g',varargin{:});
|
||||
%if(numel(mat)>1)
|
||||
formatstr=['[' repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf('],\n')]];
|
||||
%else
|
||||
% formatstr=[repmat([floatformat ','],1,size(mat,2)-1) [floatformat sprintf(',\n')]];
|
||||
%end
|
||||
|
||||
if(nargin>=2 && size(mat,1)>1 && jsonopt('ArrayIndent',1,varargin{:})==1)
|
||||
formatstr=[repmat(sprintf('\t'),1,level) formatstr];
|
||||
end
|
||||
txt=sprintf(formatstr,mat');
|
||||
txt(end-1:end)=[];
|
||||
if(islogical(mat) && jsonopt('ParseLogical',0,varargin{:})==1)
|
||||
txt=regexprep(txt,'1','true');
|
||||
txt=regexprep(txt,'0','false');
|
||||
end
|
||||
%txt=regexprep(mat2str(mat),'\s+',',');
|
||||
%txt=regexprep(txt,';',sprintf('],\n['));
|
||||
% if(nargin>=2 && size(mat,1)>1)
|
||||
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
|
||||
% end
|
||||
txt=[pre txt post];
|
||||
if(any(isinf(mat(:))))
|
||||
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
|
||||
end
|
||||
if(any(isnan(mat(:))))
|
||||
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function newname=checkname(name,varargin)
|
||||
isunpack=jsonopt('UnpackHex',1,varargin{:});
|
||||
newname=name;
|
||||
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
|
||||
return
|
||||
end
|
||||
if(isunpack)
|
||||
isoct=jsonopt('IsOctave',0,varargin{:});
|
||||
if(~isoct)
|
||||
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
|
||||
else
|
||||
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
|
||||
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
|
||||
if(isempty(pos)) return; end
|
||||
str0=name;
|
||||
pos0=[0 pend(:)' length(name)];
|
||||
newname='';
|
||||
for i=1:length(pos)
|
||||
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
|
||||
end
|
||||
if(pos(end)~=length(name))
|
||||
newname=[newname str0(pos0(end-1)+1:pos0(end))];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function newstr=escapejsonstring(str)
|
||||
newstr=str;
|
||||
isoct=exist('OCTAVE_VERSION','builtin');
|
||||
if(isoct)
|
||||
vv=sscanf(OCTAVE_VERSION,'%f');
|
||||
if(vv(1)>=3.8) isoct=0; end
|
||||
end
|
||||
if(isoct)
|
||||
escapechars={'\a','\f','\n','\r','\t','\v'};
|
||||
for i=1:length(escapechars);
|
||||
newstr=regexprep(newstr,escapechars{i},escapechars{i});
|
||||
end
|
||||
else
|
||||
escapechars={'\a','\b','\f','\n','\r','\t','\v'};
|
||||
for i=1:length(escapechars);
|
||||
newstr=regexprep(newstr,escapechars{i},regexprep(escapechars{i},'\\','\\\\'));
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,497 @@
|
||||
function json=saveubjson(rootname,obj,varargin)
|
||||
%
|
||||
% json=saveubjson(rootname,obj,filename)
|
||||
% or
|
||||
% json=saveubjson(rootname,obj,opt)
|
||||
% json=saveubjson(rootname,obj,'param1',value1,'param2',value2,...)
|
||||
%
|
||||
% convert a MATLAB object (cell, struct or array) into a Universal
|
||||
% Binary JSON (UBJSON) binary string
|
||||
%
|
||||
% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% created on 2013/08/17
|
||||
%
|
||||
% $Id: saveubjson.m 440 2014-09-17 19:59:45Z fangq $
|
||||
%
|
||||
% input:
|
||||
% rootname: name of the root-object, if set to '', will use variable name
|
||||
% obj: a MATLAB object (array, cell, cell array, struct, struct array)
|
||||
% filename: a string for the file name to save the output JSON data
|
||||
% opt: a struct for additional options, use [] if all use default
|
||||
% opt can have the following fields (first in [.|.] is the default)
|
||||
%
|
||||
% opt.FileName [''|string]: a file name to save the output JSON data
|
||||
% opt.ArrayToStruct[0|1]: when set to 0, saveubjson outputs 1D/2D
|
||||
% array in JSON array format; if sets to 1, an
|
||||
% array will be shown as a struct with fields
|
||||
% "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
|
||||
% sparse arrays, the non-zero elements will be
|
||||
% saved to _ArrayData_ field in triplet-format i.e.
|
||||
% (ix,iy,val) and "_ArrayIsSparse_" will be added
|
||||
% with a value of 1; for a complex array, the
|
||||
% _ArrayData_ array will include two columns
|
||||
% (4 for sparse) to record the real and imaginary
|
||||
% parts, and also "_ArrayIsComplex_":1 is added.
|
||||
% opt.ParseLogical [1|0]: if this is set to 1, logical array elem
|
||||
% will use true/false rather than 1/0.
|
||||
% opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
|
||||
% numerical element will be shown without a square
|
||||
% bracket, unless it is the root object; if 0, square
|
||||
% brackets are forced for any numerical arrays.
|
||||
% opt.ForceRootName [0|1]: when set to 1 and rootname is empty, saveubjson
|
||||
% will use the name of the passed obj variable as the
|
||||
% root object name; if obj is an expression and
|
||||
% does not have a name, 'root' will be used; if this
|
||||
% is set to 0 and rootname is empty, the root level
|
||||
% will be merged down to the lower level.
|
||||
% opt.JSONP [''|string]: to generate a JSONP output (JSON with padding),
|
||||
% for example, if opt.JSON='foo', the JSON data is
|
||||
% wrapped inside a function call as 'foo(...);'
|
||||
% opt.UnpackHex [1|0]: conver the 0x[hex code] output by loadjson
|
||||
% back to the string form
|
||||
% opt can be replaced by a list of ('param',value) pairs. The param
|
||||
% string is equivallent to a field in opt.
|
||||
% output:
|
||||
% json: a string in the JSON format (see http://json.org)
|
||||
%
|
||||
% examples:
|
||||
% a=struct('node',[1 9 10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
|
||||
% 'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
|
||||
% saveubjson('mesh',a)
|
||||
% saveubjson('mesh',a,'meshdata.ubj')
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
if(nargin==1)
|
||||
varname=inputname(1);
|
||||
obj=rootname;
|
||||
if(isempty(varname))
|
||||
varname='root';
|
||||
end
|
||||
rootname=varname;
|
||||
else
|
||||
varname=inputname(2);
|
||||
end
|
||||
if(length(varargin)==1 && ischar(varargin{1}))
|
||||
opt=struct('FileName',varargin{1});
|
||||
else
|
||||
opt=varargin2struct(varargin{:});
|
||||
end
|
||||
opt.IsOctave=exist('OCTAVE_VERSION','builtin');
|
||||
rootisarray=0;
|
||||
rootlevel=1;
|
||||
forceroot=jsonopt('ForceRootName',0,opt);
|
||||
if((isnumeric(obj) || islogical(obj) || ischar(obj) || isstruct(obj) || iscell(obj)) && isempty(rootname) && forceroot==0)
|
||||
rootisarray=1;
|
||||
rootlevel=0;
|
||||
else
|
||||
if(isempty(rootname))
|
||||
rootname=varname;
|
||||
end
|
||||
end
|
||||
if((isstruct(obj) || iscell(obj))&& isempty(rootname) && forceroot)
|
||||
rootname='root';
|
||||
end
|
||||
json=obj2ubjson(rootname,obj,rootlevel,opt);
|
||||
if(~rootisarray)
|
||||
json=['{' json '}'];
|
||||
end
|
||||
|
||||
jsonp=jsonopt('JSONP','',opt);
|
||||
if(~isempty(jsonp))
|
||||
json=[jsonp '(' json ')'];
|
||||
end
|
||||
|
||||
% save to a file if FileName is set, suggested by Patrick Rapin
|
||||
if(~isempty(jsonopt('FileName','',opt)))
|
||||
fid = fopen(opt.FileName, 'wb');
|
||||
fwrite(fid,json);
|
||||
fclose(fid);
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=obj2ubjson(name,item,level,varargin)
|
||||
|
||||
if(iscell(item))
|
||||
txt=cell2ubjson(name,item,level,varargin{:});
|
||||
elseif(isstruct(item))
|
||||
txt=struct2ubjson(name,item,level,varargin{:});
|
||||
elseif(ischar(item))
|
||||
txt=str2ubjson(name,item,level,varargin{:});
|
||||
else
|
||||
txt=mat2ubjson(name,item,level,varargin{:});
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=cell2ubjson(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~iscell(item))
|
||||
error('input is not a cell');
|
||||
end
|
||||
|
||||
dim=size(item);
|
||||
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
|
||||
item=reshape(item,dim(1),numel(item)/dim(1));
|
||||
dim=size(item);
|
||||
end
|
||||
len=numel(item); % let's handle 1D cell first
|
||||
if(len>1)
|
||||
if(~isempty(name))
|
||||
txt=[S_(checkname(name,varargin{:})) '[']; name='';
|
||||
else
|
||||
txt='[';
|
||||
end
|
||||
elseif(len==0)
|
||||
if(~isempty(name))
|
||||
txt=[S_(checkname(name,varargin{:})) 'Z']; name='';
|
||||
else
|
||||
txt='Z';
|
||||
end
|
||||
end
|
||||
for j=1:dim(2)
|
||||
if(dim(1)>1) txt=[txt '[']; end
|
||||
for i=1:dim(1)
|
||||
txt=[txt obj2ubjson(name,item{i,j},level+(len>1),varargin{:})];
|
||||
end
|
||||
if(dim(1)>1) txt=[txt ']']; end
|
||||
end
|
||||
if(len>1) txt=[txt ']']; end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=struct2ubjson(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~isstruct(item))
|
||||
error('input is not a struct');
|
||||
end
|
||||
dim=size(item);
|
||||
if(ndims(squeeze(item))>2) % for 3D or higher dimensions, flatten to 2D for now
|
||||
item=reshape(item,dim(1),numel(item)/dim(1));
|
||||
dim=size(item);
|
||||
end
|
||||
len=numel(item);
|
||||
|
||||
if(~isempty(name))
|
||||
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
|
||||
else
|
||||
if(len>1) txt='['; end
|
||||
end
|
||||
for j=1:dim(2)
|
||||
if(dim(1)>1) txt=[txt '[']; end
|
||||
for i=1:dim(1)
|
||||
names = fieldnames(item(i,j));
|
||||
if(~isempty(name) && len==1)
|
||||
txt=[txt S_(checkname(name,varargin{:})) '{'];
|
||||
else
|
||||
txt=[txt '{'];
|
||||
end
|
||||
if(~isempty(names))
|
||||
for e=1:length(names)
|
||||
txt=[txt obj2ubjson(names{e},getfield(item(i,j),...
|
||||
names{e}),level+(dim(1)>1)+1+(len>1),varargin{:})];
|
||||
end
|
||||
end
|
||||
txt=[txt '}'];
|
||||
end
|
||||
if(dim(1)>1) txt=[txt ']']; end
|
||||
end
|
||||
if(len>1) txt=[txt ']']; end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=str2ubjson(name,item,level,varargin)
|
||||
txt='';
|
||||
if(~ischar(item))
|
||||
error('input is not a string');
|
||||
end
|
||||
item=reshape(item, max(size(item),[1 0]));
|
||||
len=size(item,1);
|
||||
|
||||
if(~isempty(name))
|
||||
if(len>1) txt=[S_(checkname(name,varargin{:})) '[']; end
|
||||
else
|
||||
if(len>1) txt='['; end
|
||||
end
|
||||
isoct=jsonopt('IsOctave',0,varargin{:});
|
||||
for e=1:len
|
||||
val=item(e,:);
|
||||
if(len==1)
|
||||
obj=['' S_(checkname(name,varargin{:})) '' '',S_(val),''];
|
||||
if(isempty(name)) obj=['',S_(val),'']; end
|
||||
txt=[txt,'',obj];
|
||||
else
|
||||
txt=[txt,'',['',S_(val),'']];
|
||||
end
|
||||
end
|
||||
if(len>1) txt=[txt ']']; end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=mat2ubjson(name,item,level,varargin)
|
||||
if(~isnumeric(item) && ~islogical(item))
|
||||
error('input is not an array');
|
||||
end
|
||||
|
||||
if(length(size(item))>2 || issparse(item) || ~isreal(item) || ...
|
||||
isempty(item) || jsonopt('ArrayToStruct',0,varargin{:}))
|
||||
cid=I_(uint32(max(size(item))));
|
||||
if(isempty(name))
|
||||
txt=['{' S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1)) ];
|
||||
else
|
||||
if(isempty(item))
|
||||
txt=[S_(checkname(name,varargin{:})),'Z'];
|
||||
return;
|
||||
else
|
||||
txt=[S_(checkname(name,varargin{:})),'{',S_('_ArrayType_'),S_(class(item)),S_('_ArraySize_'),I_a(size(item),cid(1))];
|
||||
end
|
||||
end
|
||||
else
|
||||
if(isempty(name))
|
||||
txt=matdata2ubjson(item,level+1,varargin{:});
|
||||
else
|
||||
if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
|
||||
numtxt=regexprep(regexprep(matdata2ubjson(item,level+1,varargin{:}),'^\[',''),']','');
|
||||
txt=[S_(checkname(name,varargin{:})) numtxt];
|
||||
else
|
||||
txt=[S_(checkname(name,varargin{:})),matdata2ubjson(item,level+1,varargin{:})];
|
||||
end
|
||||
end
|
||||
return;
|
||||
end
|
||||
if(issparse(item))
|
||||
[ix,iy]=find(item);
|
||||
data=full(item(find(item)));
|
||||
if(~isreal(item))
|
||||
data=[real(data(:)),imag(data(:))];
|
||||
if(size(item,1)==1)
|
||||
% Kludge to have data's 'transposedness' match item's.
|
||||
% (Necessary for complex row vector handling below.)
|
||||
data=data';
|
||||
end
|
||||
txt=[txt,S_('_ArrayIsComplex_'),'T'];
|
||||
end
|
||||
txt=[txt,S_('_ArrayIsSparse_'),'T'];
|
||||
if(size(item,1)==1)
|
||||
% Row vector, store only column indices.
|
||||
txt=[txt,S_('_ArrayData_'),...
|
||||
matdata2ubjson([iy(:),data'],level+2,varargin{:})];
|
||||
elseif(size(item,2)==1)
|
||||
% Column vector, store only row indices.
|
||||
txt=[txt,S_('_ArrayData_'),...
|
||||
matdata2ubjson([ix,data],level+2,varargin{:})];
|
||||
else
|
||||
% General case, store row and column indices.
|
||||
txt=[txt,S_('_ArrayData_'),...
|
||||
matdata2ubjson([ix,iy,data],level+2,varargin{:})];
|
||||
end
|
||||
else
|
||||
if(isreal(item))
|
||||
txt=[txt,S_('_ArrayData_'),...
|
||||
matdata2ubjson(item(:)',level+2,varargin{:})];
|
||||
else
|
||||
txt=[txt,S_('_ArrayIsComplex_'),'T'];
|
||||
txt=[txt,S_('_ArrayData_'),...
|
||||
matdata2ubjson([real(item(:)) imag(item(:))],level+2,varargin{:})];
|
||||
end
|
||||
end
|
||||
txt=[txt,'}'];
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function txt=matdata2ubjson(mat,level,varargin)
|
||||
if(isempty(mat))
|
||||
txt='Z';
|
||||
return;
|
||||
end
|
||||
if(size(mat,1)==1)
|
||||
level=level-1;
|
||||
end
|
||||
type='';
|
||||
hasnegtive=(mat<0);
|
||||
if(isa(mat,'integer') || isinteger(mat) || (isfloat(mat) && all(mod(mat(:),1) == 0)))
|
||||
if(isempty(hasnegtive))
|
||||
if(max(mat(:))<=2^8)
|
||||
type='U';
|
||||
end
|
||||
end
|
||||
if(isempty(type))
|
||||
% todo - need to consider negative ones separately
|
||||
id= histc(abs(max(mat(:))),[0 2^7 2^15 2^31 2^63]);
|
||||
if(isempty(find(id)))
|
||||
error('high-precision data is not yet supported');
|
||||
end
|
||||
key='iIlL';
|
||||
type=key(find(id));
|
||||
end
|
||||
txt=[I_a(mat(:),type,size(mat))];
|
||||
elseif(islogical(mat))
|
||||
logicalval='FT';
|
||||
if(numel(mat)==1)
|
||||
txt=logicalval(mat+1);
|
||||
else
|
||||
txt=['[$U#' I_a(size(mat),'l') typecast(swapbytes(uint8(mat(:)')),'uint8')];
|
||||
end
|
||||
else
|
||||
if(numel(mat)==1)
|
||||
txt=['[' D_(mat) ']'];
|
||||
else
|
||||
txt=D_a(mat(:),'D',size(mat));
|
||||
end
|
||||
end
|
||||
|
||||
%txt=regexprep(mat2str(mat),'\s+',',');
|
||||
%txt=regexprep(txt,';',sprintf('],['));
|
||||
% if(nargin>=2 && size(mat,1)>1)
|
||||
% txt=regexprep(txt,'\[',[repmat(sprintf('\t'),1,level) '[']);
|
||||
% end
|
||||
if(any(isinf(mat(:))))
|
||||
txt=regexprep(txt,'([-+]*)Inf',jsonopt('Inf','"$1_Inf_"',varargin{:}));
|
||||
end
|
||||
if(any(isnan(mat(:))))
|
||||
txt=regexprep(txt,'NaN',jsonopt('NaN','"_NaN_"',varargin{:}));
|
||||
end
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function newname=checkname(name,varargin)
|
||||
isunpack=jsonopt('UnpackHex',1,varargin{:});
|
||||
newname=name;
|
||||
if(isempty(regexp(name,'0x([0-9a-fA-F]+)_','once')))
|
||||
return
|
||||
end
|
||||
if(isunpack)
|
||||
isoct=jsonopt('IsOctave',0,varargin{:});
|
||||
if(~isoct)
|
||||
newname=regexprep(name,'(^x|_){1}0x([0-9a-fA-F]+)_','${native2unicode(hex2dec($2))}');
|
||||
else
|
||||
pos=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','start');
|
||||
pend=regexp(name,'(^x|_){1}0x([0-9a-fA-F]+)_','end');
|
||||
if(isempty(pos)) return; end
|
||||
str0=name;
|
||||
pos0=[0 pend(:)' length(name)];
|
||||
newname='';
|
||||
for i=1:length(pos)
|
||||
newname=[newname str0(pos0(i)+1:pos(i)-1) char(hex2dec(str0(pos(i)+3:pend(i)-1)))];
|
||||
end
|
||||
if(pos(end)~=length(name))
|
||||
newname=[newname str0(pos0(end-1)+1:pos0(end))];
|
||||
end
|
||||
end
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
function val=S_(str)
|
||||
if(length(str)==1)
|
||||
val=['C' str];
|
||||
else
|
||||
val=['S' I_(int32(length(str))) str];
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
function val=I_(num)
|
||||
if(~isinteger(num))
|
||||
error('input is not an integer');
|
||||
end
|
||||
if(num>=0 && num<255)
|
||||
val=['U' data2byte(swapbytes(cast(num,'uint8')),'uint8')];
|
||||
return;
|
||||
end
|
||||
key='iIlL';
|
||||
cid={'int8','int16','int32','int64'};
|
||||
for i=1:4
|
||||
if((num>0 && num<2^(i*8-1)) || (num<0 && num>=-2^(i*8-1)))
|
||||
val=[key(i) data2byte(swapbytes(cast(num,cid{i})),'uint8')];
|
||||
return;
|
||||
end
|
||||
end
|
||||
error('unsupported integer');
|
||||
|
||||
%%-------------------------------------------------------------------------
|
||||
function val=D_(num)
|
||||
if(~isfloat(num))
|
||||
error('input is not a float');
|
||||
end
|
||||
|
||||
if(isa(num,'single'))
|
||||
val=['d' data2byte(num,'uint8')];
|
||||
else
|
||||
val=['D' data2byte(num,'uint8')];
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
function data=I_a(num,type,dim,format)
|
||||
id=find(ismember('iUIlL',type));
|
||||
|
||||
if(id==0)
|
||||
error('unsupported integer array');
|
||||
end
|
||||
|
||||
% based on UBJSON specs, all integer types are stored in big endian format
|
||||
|
||||
if(id==1)
|
||||
data=data2byte(swapbytes(int8(num)),'uint8');
|
||||
blen=1;
|
||||
elseif(id==2)
|
||||
data=data2byte(swapbytes(uint8(num)),'uint8');
|
||||
blen=1;
|
||||
elseif(id==3)
|
||||
data=data2byte(swapbytes(int16(num)),'uint8');
|
||||
blen=2;
|
||||
elseif(id==4)
|
||||
data=data2byte(swapbytes(int32(num)),'uint8');
|
||||
blen=4;
|
||||
elseif(id==5)
|
||||
data=data2byte(swapbytes(int64(num)),'uint8');
|
||||
blen=8;
|
||||
end
|
||||
|
||||
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
|
||||
format='opt';
|
||||
end
|
||||
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
|
||||
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
|
||||
cid=I_(uint32(max(dim)));
|
||||
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
|
||||
else
|
||||
data=['$' type '#' I_(int32(numel(data)/blen)) data(:)'];
|
||||
end
|
||||
data=['[' data(:)'];
|
||||
else
|
||||
data=reshape(data,blen,numel(data)/blen);
|
||||
data(2:blen+1,:)=data;
|
||||
data(1,:)=type;
|
||||
data=data(:)';
|
||||
data=['[' data(:)' ']'];
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
function data=D_a(num,type,dim,format)
|
||||
id=find(ismember('dD',type));
|
||||
|
||||
if(id==0)
|
||||
error('unsupported float array');
|
||||
end
|
||||
|
||||
if(id==1)
|
||||
data=data2byte(single(num),'uint8');
|
||||
elseif(id==2)
|
||||
data=data2byte(double(num),'uint8');
|
||||
end
|
||||
|
||||
if(nargin>=3 && length(dim)>=2 && prod(dim)~=dim(2))
|
||||
format='opt';
|
||||
end
|
||||
if((nargin<4 || strcmp(format,'opt')) && numel(num)>1)
|
||||
if(nargin>=3 && (length(dim)==1 || (length(dim)>=2 && prod(dim)~=dim(2))))
|
||||
cid=I_(uint32(max(dim)));
|
||||
data=['$' type '#' I_a(dim,cid(1)) data(:)'];
|
||||
else
|
||||
data=['$' type '#' I_(int32(numel(data)/(id*4))) data(:)'];
|
||||
end
|
||||
data=['[' data];
|
||||
else
|
||||
data=reshape(data,(id*4),length(data)/(id*4));
|
||||
data(2:(id*4+1),:)=data;
|
||||
data(1,:)=type;
|
||||
data=data(:)';
|
||||
data=['[' data(:)' ']'];
|
||||
end
|
||||
%%-------------------------------------------------------------------------
|
||||
function bytes=data2byte(varargin)
|
||||
bytes=typecast(varargin{:});
|
||||
bytes=bytes(:)';
|
||||
@@ -0,0 +1,371 @@
|
||||
function [output,extras] = urlread2(urlChar,method,body,headersIn,varargin)
|
||||
%urlread2 Makes HTTP requests and processes response
|
||||
%
|
||||
% [output,extras] = urlread2(urlChar, *method, *body, *headersIn, varargin)
|
||||
%
|
||||
% * indicates optional inputs that must be entered in place
|
||||
%
|
||||
% UNDOCUMENTED MATLAB VERSION
|
||||
%
|
||||
% EXAMPLE CALLING FORMS
|
||||
% ... = urlread2(urlChar)
|
||||
% ... = urlread2(urlChar,'GET','',[],prop1,value1,prop2,value2,etc)
|
||||
% ... = urlread2(urlChar,'POST',body,headers)
|
||||
%
|
||||
% FEATURES
|
||||
% =======================================================================
|
||||
% 1) Allows specification of any HTTP method
|
||||
% 2) Allows specification of any header. Very little is hard-coded
|
||||
% in for header handling.
|
||||
% 3) Returns response status and headers
|
||||
% 4) Should handle unicode properly ...
|
||||
%
|
||||
% OUTPUTS
|
||||
% =======================================================================
|
||||
% output : body of the response, either text or binary depending upon
|
||||
% CAST_OUTPUT property
|
||||
% extras : (structure)
|
||||
% .allHeaders - stucture, fields have cellstr values, HTTP headers may
|
||||
% may be repeated but will have a single field entry, with each
|
||||
% repeat's value another being another entry in the cellstr, for
|
||||
% example:
|
||||
% .Set_Cookie = {'first_value' 'second_value'}
|
||||
% .firstHeaders - (structure), variable fields, contains the first
|
||||
% string entry for each field in allHeaders, this
|
||||
% structure can be used to avoid dereferencing a cell
|
||||
% for fields you expect not to be repeated ...
|
||||
% EXAMPLE:
|
||||
% .Response : 'HTTP/1.1 200 OK'}
|
||||
% .Server : 'nginx'
|
||||
% .Date : 'Tue, 29 Nov 2011 02:23:16 GMT'
|
||||
% .Content_Type : 'text/html; charset=UTF-8'
|
||||
% .Content_Length : '109155'
|
||||
% .Connection : 'keep-alive'
|
||||
% .Vary : 'Accept-Encoding, User-Agent'
|
||||
% .Cache_Control : 'max-age=60, private'
|
||||
% .Set_Cookie : 'first_value'
|
||||
% .status - (structure)
|
||||
% .value : numeric value of status, ex. 200
|
||||
% .msg : message that goes along with status, ex. 'OK'
|
||||
% .url - eventual url that led to output, this can change from
|
||||
% the input with redirects, see FOLLOW_REDIRECTS
|
||||
% .isGood - (logical) I believe this is an indicator of the presence of 400
|
||||
% or 500 status codes (see status.value) but more
|
||||
% testing is needed. In other words, true if status.value < 400.
|
||||
% In code, set true if the response was obtainable without
|
||||
% resorting to checking the error stream.
|
||||
%
|
||||
% INPUTS
|
||||
% =======================================================================
|
||||
% urlChar : The full url, must include scheme (http, https)
|
||||
% method : examples: 'GET' 'POST' etc
|
||||
% body : (vector)(char, uint8 or int8) body to write, generally used
|
||||
% with POST or PUT, use of uint8 or int8 ensures that the
|
||||
% body input is not manipulated before sending, char is sent
|
||||
% via unicode2native function with ENCODING input (see below)
|
||||
% headersIn : (structure array), use empty [] or '' if no headers are needed
|
||||
% but varargin property/value pairs are, multiple headers
|
||||
% may be passed in as a structure array
|
||||
% .name - (string), name of the header, a name property is used
|
||||
% instead of a field because the name must match a valid
|
||||
% header
|
||||
% .value - (string), value to use
|
||||
%
|
||||
% OPTIONAL INPUTS (varargin, property/value pairs)
|
||||
% =======================================================================
|
||||
% CAST_OUTPUT : (default true) output is uint8, useful if the body
|
||||
% of the response is not text
|
||||
% ENCODING : (default ''), ENCODING input to function unicode2native
|
||||
% FOLLOW_REDIRECTS : (default true), if false 3xx status codes will
|
||||
% be returned and need to be handled by the user,
|
||||
% note this does not handle javascript or meta tag
|
||||
% redirects, just server based ones
|
||||
% READ_TIMEOUT : (default 0), 0 means no timeout, value is in
|
||||
% milliseconds
|
||||
%
|
||||
% EXAMPLES
|
||||
% =======================================================================
|
||||
% GET:
|
||||
% --------------------------------------------
|
||||
% url = 'http://www.mathworks.com/matlabcentral/fileexchange/';
|
||||
% query = 'urlread2';
|
||||
% params = {'term' query};
|
||||
% queryString = http_paramsToString(params,1);
|
||||
% url = [url '?' queryString];
|
||||
% [output,extras] = urlread2(url);
|
||||
%
|
||||
% POST:
|
||||
% --------------------------------------------
|
||||
% url = 'http://posttestserver.com/post.php';
|
||||
% params = {'testChars' char([2500 30000]) 'new code' '?'};
|
||||
% [paramString,header] = http_paramsToString(params,1);
|
||||
% [output,extras] = urlread2(url,'POST',paramString,header);
|
||||
%
|
||||
% From behind a firewall, use the Preferences to set your proxy server.
|
||||
%
|
||||
% See Also:
|
||||
% http_paramsToString
|
||||
% unicode2native
|
||||
% native2unicode
|
||||
%
|
||||
% Subfunctions:
|
||||
% fixHeaderCasing - small subfunction to fix case errors encountered in real
|
||||
% world, requires updating when casing doesn't match expected form, like
|
||||
% if someone sent the header content-Encoding instead of
|
||||
% Content-Encoding
|
||||
%
|
||||
% Based on original urlread code by Matthew J. Simoneau
|
||||
%
|
||||
% VERSION = 1.1
|
||||
|
||||
in.CAST_OUTPUT = true;
|
||||
in.FOLLOW_REDIRECTS = true;
|
||||
in.READ_TIMEOUT = 0;
|
||||
in.ENCODING = '';
|
||||
|
||||
%Input handling
|
||||
%---------------------------------------
|
||||
if ~isempty(varargin)
|
||||
for i = 1:2:numel(varargin)
|
||||
prop = upper(varargin{i});
|
||||
value = varargin{i+1};
|
||||
if isfield(in,prop)
|
||||
in.(prop) = value;
|
||||
else
|
||||
error('Unrecognized input to function: %s',prop)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ~exist('method','var') || isempty(method), method = 'GET'; end
|
||||
if ~exist('body','var'), body = ''; end
|
||||
if ~exist('headersIn','var'), headersIn = []; end
|
||||
|
||||
assert(usejava('jvm'),'Function requires Java')
|
||||
|
||||
import com.mathworks.mlwidgets.io.InterruptibleStreamCopier;
|
||||
com.mathworks.mlwidgets.html.HTMLPrefs.setProxySettings %Proxy settings need to be set
|
||||
|
||||
%Create a urlConnection.
|
||||
%-----------------------------------
|
||||
urlConnection = getURLConnection(urlChar);
|
||||
%For HTTP uses sun.net.www.protocol.http.HttpURLConnection
|
||||
%Might use ice.net.HttpURLConnection but this has more overhead
|
||||
|
||||
%SETTING PROPERTIES
|
||||
%-------------------------------------------------------
|
||||
urlConnection.setRequestMethod(upper(method));
|
||||
urlConnection.setFollowRedirects(in.FOLLOW_REDIRECTS);
|
||||
urlConnection.setReadTimeout(in.READ_TIMEOUT);
|
||||
|
||||
for iHeader = 1:length(headersIn)
|
||||
curHeader = headersIn(iHeader);
|
||||
urlConnection.setRequestProperty(curHeader.name,curHeader.value);
|
||||
end
|
||||
|
||||
if ~isempty(body)
|
||||
%Ensure vector?
|
||||
if size(body,1) > 1
|
||||
if size(body,2) > 1
|
||||
error('Input parameter to function: body, must be a vector')
|
||||
else
|
||||
body = body';
|
||||
end
|
||||
end
|
||||
|
||||
if ischar(body)
|
||||
%NOTE: '' defaults to Matlab's default encoding scheme
|
||||
body = unicode2native(body,in.ENCODING);
|
||||
elseif ~(strcmp(class(body),'uint8') || strcmp(class(body),'int8'))
|
||||
error('Function input: body, should be of class char, uint8, or int8, detected: %s',class(body))
|
||||
end
|
||||
|
||||
urlConnection.setRequestProperty('Content-Length',int2str(length(body)));
|
||||
urlConnection.setDoOutput(true);
|
||||
outputStream = urlConnection.getOutputStream;
|
||||
outputStream.write(body);
|
||||
outputStream.close;
|
||||
else
|
||||
urlConnection.setRequestProperty('Content-Length','0');
|
||||
end
|
||||
|
||||
%==========================================================================
|
||||
% Read the data from the connection.
|
||||
%==========================================================================
|
||||
%This should be done first because it tells us if things are ok or not
|
||||
%NOTE: If there is an error, functions below using urlConnection, notably
|
||||
%getResponseCode, will fail as well
|
||||
try
|
||||
inputStream = urlConnection.getInputStream;
|
||||
isGood = true;
|
||||
catch ME
|
||||
isGood = false;
|
||||
%NOTE: HTTP error codes will throw an error here, we'll allow those for now
|
||||
%We might also get another error in which case the inputStream will be
|
||||
%undefined, those we will throw here
|
||||
inputStream = urlConnection.getErrorStream;
|
||||
|
||||
if isempty(inputStream)
|
||||
msg = ME.message;
|
||||
I = strfind(msg,char([13 10 9])); %see example by setting timeout to 1
|
||||
%Should remove the barf of the stack, at ... at ... at ... etc
|
||||
%Likely that this could be improved ... (generate link with full msg)
|
||||
if ~isempty(I)
|
||||
msg = msg(1:I(1)-1);
|
||||
end
|
||||
fprintf(2,'Response stream is undefined\n below is a Java Error dump (truncated):\n');
|
||||
error(msg)
|
||||
end
|
||||
end
|
||||
|
||||
%POPULATING HEADERS
|
||||
%--------------------------------------------------------------------------
|
||||
allHeaders = struct;
|
||||
allHeaders.Response = {char(urlConnection.getHeaderField(0))};
|
||||
done = false;
|
||||
headerIndex = 0;
|
||||
|
||||
while ~done
|
||||
headerIndex = headerIndex + 1;
|
||||
headerValue = char(urlConnection.getHeaderField(headerIndex));
|
||||
if ~isempty(headerValue)
|
||||
headerName = char(urlConnection.getHeaderFieldKey(headerIndex));
|
||||
headerName = fixHeaderCasing(headerName); %NOT YET FINISHED
|
||||
|
||||
%Important, for name safety all hyphens are replace with underscores
|
||||
headerName(headerName == '-') = '_';
|
||||
if isfield(allHeaders,headerName)
|
||||
allHeaders.(headerName) = [allHeaders.(headerName) headerValue];
|
||||
else
|
||||
allHeaders.(headerName) = {headerValue};
|
||||
end
|
||||
else
|
||||
done = true;
|
||||
end
|
||||
end
|
||||
|
||||
firstHeaders = struct;
|
||||
fn = fieldnames(allHeaders);
|
||||
for iHeader = 1:length(fn)
|
||||
curField = fn{iHeader};
|
||||
firstHeaders.(curField) = allHeaders.(curField){1};
|
||||
end
|
||||
|
||||
status = struct(...
|
||||
'value', urlConnection.getResponseCode(),...
|
||||
'msg', char(urlConnection.getResponseMessage));
|
||||
|
||||
%PROCESSING OF OUTPUT
|
||||
%----------------------------------------------------------
|
||||
byteArrayOutputStream = java.io.ByteArrayOutputStream;
|
||||
% This StreamCopier is unsupported and may change at any time. OH GREAT :/
|
||||
isc = InterruptibleStreamCopier.getInterruptibleStreamCopier;
|
||||
isc.copyStream(inputStream,byteArrayOutputStream);
|
||||
inputStream.close;
|
||||
byteArrayOutputStream.close;
|
||||
|
||||
if in.CAST_OUTPUT
|
||||
charset = '';
|
||||
|
||||
%Extraction of character set from Content-Type header if possible
|
||||
if isfield(firstHeaders,'Content_Type')
|
||||
text = firstHeaders.Content_Type;
|
||||
%Always open to regexp improvements
|
||||
charset = regexp(text,'(?<=charset=)[^\s]*','match','once');
|
||||
end
|
||||
|
||||
if ~isempty(charset)
|
||||
output = native2unicode(typecast(byteArrayOutputStream.toByteArray','uint8'),charset);
|
||||
else
|
||||
output = char(typecast(byteArrayOutputStream.toByteArray','uint8'));
|
||||
end
|
||||
else
|
||||
%uint8 is more useful for later charecter conversions
|
||||
%uint8 or int8 is somewhat arbitary at this point
|
||||
output = typecast(byteArrayOutputStream.toByteArray','uint8');
|
||||
end
|
||||
|
||||
extras = struct;
|
||||
extras.allHeaders = allHeaders;
|
||||
extras.firstHeaders = firstHeaders;
|
||||
extras.status = status;
|
||||
%Gets eventual url even with redirection
|
||||
extras.url = char(urlConnection.getURL);
|
||||
extras.isGood = isGood;
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
function headerNameOut = fixHeaderCasing(headerName)
|
||||
%fixHeaderCasing Forces standard casing of headers
|
||||
%
|
||||
% headerNameOut = fixHeaderCasing(headerName)
|
||||
%
|
||||
% This is important for field access in a structure which
|
||||
% is case sensitive
|
||||
%
|
||||
% Not yet finished.
|
||||
% I've been adding to this function as problems come along
|
||||
|
||||
switch lower(headerName)
|
||||
case 'location'
|
||||
headerNameOut = 'Location';
|
||||
case 'content_type'
|
||||
headerNameOut = 'Content_Type';
|
||||
otherwise
|
||||
headerNameOut = headerName;
|
||||
end
|
||||
end
|
||||
|
||||
%==========================================================================
|
||||
%==========================================================================
|
||||
%==========================================================================
|
||||
|
||||
function urlConnection = getURLConnection(urlChar)
|
||||
%getURLConnection
|
||||
%
|
||||
% urlConnection = getURLConnection(urlChar)
|
||||
|
||||
% Determine the protocol (before the ":").
|
||||
protocol = urlChar(1:find(urlChar==':',1)-1);
|
||||
|
||||
|
||||
% Try to use the native handler, not the ice.* classes.
|
||||
try
|
||||
switch protocol
|
||||
case 'http'
|
||||
%http://www.docjar.com/docs/api/sun/net/www/protocol/http/HttpURLConnection.html
|
||||
handler = sun.net.www.protocol.http.Handler;
|
||||
case 'https'
|
||||
handler = sun.net.www.protocol.https.Handler;
|
||||
end
|
||||
catch ME
|
||||
handler = [];
|
||||
end
|
||||
|
||||
% Create the URL object.
|
||||
try
|
||||
if isempty(handler)
|
||||
url = java.net.URL(urlChar);
|
||||
else
|
||||
url = java.net.URL([],urlChar,handler);
|
||||
end
|
||||
catch ME
|
||||
error('Failure to parse URL or protocol not supported for:\nURL: %s',urlChar);
|
||||
end
|
||||
|
||||
% Get the proxy information using MathWorks facilities for unified proxy
|
||||
% preference settings.
|
||||
mwtcp = com.mathworks.net.transport.MWTransportClientPropertiesFactory.create();
|
||||
proxy = mwtcp.getProxy();
|
||||
|
||||
% Open a connection to the URL.
|
||||
if isempty(proxy)
|
||||
urlConnection = url.openConnection;
|
||||
else
|
||||
urlConnection = url.openConnection(proxy);
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
==========================================================================
|
||||
Unicode & Matlab
|
||||
==========================================================================
|
||||
native2unicode - works with uint8, fails with char
|
||||
|
||||
Taking a unicode character and encoding as bytes:
|
||||
unicode2native(char(1002),'UTF-8')
|
||||
back to the character:
|
||||
native2unicode(uint8([207 170]),'UTF-8')
|
||||
this doesn't work:
|
||||
native2unicode(char([207 170]),'UTF-8')
|
||||
in documentation: If BYTES is a CHAR vector, it is returned unchanged.
|
||||
|
||||
Java - only supports int8
|
||||
Matlab to Java -> uint8 or int8 to bytes
|
||||
Java to Matlab -> bytes to int8
|
||||
char - 16 bit
|
||||
|
||||
Maintenance of underlying bytes:
|
||||
typecast(java.lang.String(uint8(250)).getBytes,'uint8') = 250
|
||||
see documentation: Handling Data Returned from a Java Method
|
||||
|
||||
Command Window difficulty
|
||||
--------------------------------------------------------------------
|
||||
The typical font in the Matlab command window will often fail to render
|
||||
unicode properly. I often can see unicode better in the variable editor
|
||||
although this may be fixed if you change your font preferences ...
|
||||
Copying unicode from the command window often results in the
|
||||
generations of the value 26 (aka substitute)
|
||||
|
||||
More documentation on input/output to urlread2 to follow eventually ...
|
||||
|
||||
small notes to self:
|
||||
for output
|
||||
native2unicode(uint8(output),encoding)
|
||||
|
||||
==========================================================================
|
||||
HTTP Headers
|
||||
==========================================================================
|
||||
Handling of repeated http readers is a bit of a tricky situation. Most
|
||||
headers are not repeated although sometimes http clients will assume this
|
||||
for too many headers which can result in a problem if you want to see
|
||||
duplicated headers. I've passed the problem onto the user who can decide
|
||||
to handle it how they wish instead of providing the right solution, which
|
||||
after some brief searching, I am not sure exists.
|
||||
|
||||
==========================================================================
|
||||
PROBLEMS
|
||||
==========================================================================
|
||||
1) Page requires following a redirect:
|
||||
%-------------------------------------------
|
||||
ref: http://www.mathworks.com/matlabcentral/newsreader/view_thread/302571
|
||||
fix: FOLLOW_REDIRECTS is enabled by default, you're fine.
|
||||
|
||||
2) Basic authentication required:
|
||||
%------------------------------------------
|
||||
Create and pass in the following header:
|
||||
user = 'test';
|
||||
password = 'test';
|
||||
encoder = sun.misc.BASE64Encoder();
|
||||
str = java.lang.String([user ':' password]) %NOTE: format may be
|
||||
%different for your server
|
||||
header = http_createHeader('Authorization',char(encoder.encode(str.getBytes())))
|
||||
NOTE: Ideally you would make this a function
|
||||
|
||||
3) The text returned doesn't make sense.
|
||||
%-----------------------------------------
|
||||
The text may not be encoded correctly. Requires native2unicode function.
|
||||
See Unicode & Matlab section above.
|
||||
|
||||
4) I get a different result in my web browser than I do in Matlab
|
||||
%-----------------------------------------
|
||||
This is generally seen for two reasons.
|
||||
1 - The easiest and silly reason is user agent filtering.
|
||||
When you make a request you identify yourself
|
||||
as being a particular "broswer" or "user agent". Setting a header
|
||||
with the user agent of the browser may fix the problem.
|
||||
See: http://en.wikipedia.org/wiki/User_agent
|
||||
See: http://whatsmyuseragent.com
|
||||
value = ''
|
||||
header = http_createHeader('User-Agent',value);
|
||||
2 - You are not processing cookies and the server is not sending
|
||||
you information because you haven't sent it cookies (everyone likes em!)
|
||||
I've implemented cookie support but it requires some extra files that
|
||||
I need to clean up. Feel free to email me if you'd really like to have them.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
function opt=varargin2struct(varargin)
|
||||
%
|
||||
% opt=varargin2struct('param1',value1,'param2',value2,...)
|
||||
% or
|
||||
% opt=varargin2struct(...,optstruct,...)
|
||||
%
|
||||
% convert a series of input parameters into a structure
|
||||
%
|
||||
% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
|
||||
% date: 2012/12/22
|
||||
%
|
||||
% input:
|
||||
% 'param', value: the input parameters should be pairs of a string and a value
|
||||
% optstruct: if a parameter is a struct, the fields will be merged to the output struct
|
||||
%
|
||||
% output:
|
||||
% opt: a struct where opt.param1=value1, opt.param2=value2 ...
|
||||
%
|
||||
% license:
|
||||
% Simplified BSD License
|
||||
%
|
||||
% -- this function is part of jsonlab toolbox (http://iso2mesh.sf.net/cgi-bin/index.cgi?jsonlab)
|
||||
%
|
||||
|
||||
len=length(varargin);
|
||||
opt=struct;
|
||||
if(len==0) return; end
|
||||
i=1;
|
||||
while(i<=len)
|
||||
if(isstruct(varargin{i}))
|
||||
opt=mergestruct(opt,varargin{i});
|
||||
elseif(ischar(varargin{i}) && i<len)
|
||||
opt=setfield(opt,varargin{i},varargin{i+1});
|
||||
i=i+1;
|
||||
else
|
||||
error('input must be in the form of ...,''name'',value,... pairs or structs');
|
||||
end
|
||||
i=i+1;
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user