savejson

PURPOSE ^

SAVEJSON JSON encoder and emitter.

SYNOPSIS ^

function json = savejson(object, varargin)

DESCRIPTION ^

SAVEJSON  JSON encoder and emitter.

  Syntax:
    JSON = SAVEJSON(OBJECT)
    SAVEJSON(OBJECT, FILENAME)

  Description:
    JSON = SAVEJSON(OBJECT) serializes the value of OBJECT in string JSON
    encoded in Javascript Object Notation format (JSON).

    SAVEJSON(OBJECT, FILENAME) performs the same conversion but prints 
    it to the file named by string FILENAME.

  Notes:
    This function is inspired by a previous function by Tomeu Garau with the
    same name. He is the true glider man. Main changes are:
      - Added support for string output.
      - Added support for automatic creation of target directory if needed.
      - Changed NaN mapping from string 'NaN' to value null.
      - Changed character array mapping: only row char vectors map to strings 
        and control characters are escaped properly.

    There is no one-to-one map between MATLAB/Octave values and JSON values.
    The conversion is done according to this rules:
      - Boolean scalars map to corresponding boolean literals (true or false).
      - Numeric scalars map to corresponding numeric literals, except from NaN 
        which maps to null (because it is not a valid JSON value).
      - Structs map to objects with field names as keys and field values as
        values mapped according to this same set of rules.
      - Strings (character row vectors) are converted to string literals
        escaping characters according to section 2.5 of RFC in references.
      - Other arrays (either character arrays, numeric arrays, struct arrays 
        or cell arrays) map to flat arrays in column major order. 
        Dimensionality and shape information is lost.

  References:
    Crockford, D.; 2006:
    The application/json Media Type for JavaScript Object Notation (JSON).
    <http://www.ietf.org/rfc/rfc4627.txt>

  Examples:
    % Encode to string:
    json = savejson([])
    json = savejson({})
    json = savejson(struct())
    json = savejson(25)
    json = savejson(NaN)
    json = savejson(true)
    json = savejson(false)
    json = savejson(rand(1,10))
    json = savejson(...
      {sprintf(['escape this:' ...
                ' \b (backspace) \f (form feed) \n (line feed) \t (tab)' ...
                ' \r (carriage return) \x001A (escaped unicode character)' ...
                ' " (quotation mark) \\ (backslash)'])})
    json = savejson(struct('field1', {'a', 'b', 'c'}, ...
                            'field2', {[1 2], [3 5], [4 pi]}))
    % Encode to file:
    json = savejson(rand(1,10), 'json/example.json')

  See also:
    LOADJSON
    FOPEN
    FWRITE
    FCLOSE

  Authors:
    Joan Pau Beltran  <joanpau.beltran@socib.cat>

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

DOWNLOAD ^

savejson.m

SOURCE CODE ^

0001 function json = savejson(object, varargin)
0002 %SAVEJSON  JSON encoder and emitter.
0003 %
0004 %  Syntax:
0005 %    JSON = SAVEJSON(OBJECT)
0006 %    SAVEJSON(OBJECT, FILENAME)
0007 %
0008 %  Description:
0009 %    JSON = SAVEJSON(OBJECT) serializes the value of OBJECT in string JSON
0010 %    encoded in Javascript Object Notation format (JSON).
0011 %
0012 %    SAVEJSON(OBJECT, FILENAME) performs the same conversion but prints
0013 %    it to the file named by string FILENAME.
0014 %
0015 %  Notes:
0016 %    This function is inspired by a previous function by Tomeu Garau with the
0017 %    same name. He is the true glider man. Main changes are:
0018 %      - Added support for string output.
0019 %      - Added support for automatic creation of target directory if needed.
0020 %      - Changed NaN mapping from string 'NaN' to value null.
0021 %      - Changed character array mapping: only row char vectors map to strings
0022 %        and control characters are escaped properly.
0023 %
0024 %    There is no one-to-one map between MATLAB/Octave values and JSON values.
0025 %    The conversion is done according to this rules:
0026 %      - Boolean scalars map to corresponding boolean literals (true or false).
0027 %      - Numeric scalars map to corresponding numeric literals, except from NaN
0028 %        which maps to null (because it is not a valid JSON value).
0029 %      - Structs map to objects with field names as keys and field values as
0030 %        values mapped according to this same set of rules.
0031 %      - Strings (character row vectors) are converted to string literals
0032 %        escaping characters according to section 2.5 of RFC in references.
0033 %      - Other arrays (either character arrays, numeric arrays, struct arrays
0034 %        or cell arrays) map to flat arrays in column major order.
0035 %        Dimensionality and shape information is lost.
0036 %
0037 %  References:
0038 %    Crockford, D.; 2006:
0039 %    The application/json Media Type for JavaScript Object Notation (JSON).
0040 %    <http://www.ietf.org/rfc/rfc4627.txt>
0041 %
0042 %  Examples:
0043 %    % Encode to string:
0044 %    json = savejson([])
0045 %    json = savejson({})
0046 %    json = savejson(struct())
0047 %    json = savejson(25)
0048 %    json = savejson(NaN)
0049 %    json = savejson(true)
0050 %    json = savejson(false)
0051 %    json = savejson(rand(1,10))
0052 %    json = savejson(...
0053 %      {sprintf(['escape this:' ...
0054 %                ' \b (backspace) \f (form feed) \n (line feed) \t (tab)' ...
0055 %                ' \r (carriage return) \x001A (escaped unicode character)' ...
0056 %                ' " (quotation mark) \\ (backslash)'])})
0057 %    json = savejson(struct('field1', {'a', 'b', 'c'}, ...
0058 %                            'field2', {[1 2], [3 5], [4 pi]}))
0059 %    % Encode to file:
0060 %    json = savejson(rand(1,10), 'json/example.json')
0061 %
0062 %  See also:
0063 %    LOADJSON
0064 %    FOPEN
0065 %    FWRITE
0066 %    FCLOSE
0067 %
0068 %  Authors:
0069 %    Joan Pau Beltran  <joanpau.beltran@socib.cat>
0070 
0071 %  Copyright (C) 2013-2016
0072 %  ICTS SOCIB - Servei d'observacio i prediccio costaner de les Illes Balears
0073 %  <http://www.socib.es>
0074 %
0075 %  This program is free software: you can redistribute it and/or modify
0076 %  it under the terms of the GNU General Public License as published by
0077 %  the Free Software Foundation, either version 3 of the License, or
0078 %  (at your option) any later version.
0079 %
0080 %  This program is distributed in the hope that it will be useful,
0081 %  but WITHOUT ANY WARRANTY; without even the implied warranty of
0082 %  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0083 %  GNU General Public License for more details.
0084 %
0085 %  You should have received a copy of the GNU General Public License
0086 %  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0087 
0088   error(nargchk(1, 2, nargin, 'struct'));
0089   
0090   if isscalar(object) && isstruct(object)
0091     json = savejsonObject(object);
0092   else
0093     json = savejsonArray(object);
0094   end
0095   
0096   if nargin > 1
0097     filename = varargin{1};
0098     [filepath, ~, ~] = fileparts(filename);
0099     % MATLAB does not provide a proper way to check if a relative path points to
0100     % an existing directory (EXIST checks for existance in the whole load path).
0101     [status, attrout] = fileattrib(filepath);
0102     if ~status
0103       [success, message] = mkdir(filepath);
0104       if ~success
0105         error('glider_toolbox:savejson:DirectoryError', ...
0106               'Could not create directory %s: %s.', filepath, message);
0107       end
0108     elseif ~attrout.directory
0109       error('glider_toolbox:savejson:DirectoryError', ...
0110             'Not a directory %s.', filepath);
0111     end
0112     [fid, message] = fopen(filename, 'w');
0113     if fid < 0 
0114       error('glider_toolbox:savejson:FileError', ...
0115             'Could not open file for writing %s: %s.', filename, message);
0116     end
0117     count = fwrite(fid, json, 'char');
0118     status = fclose(fid);
0119     if status < 0
0120       error('glider_toolbox:savejson:FileError', ...
0121             'Could not close file %s: %d characters written.', filename, count);
0122     end
0123   end
0124   
0125 end
0126 
0127 function json = savejsonObject(object)
0128 %SAVEJSONOBJECT  Encode a scalar struct as a JSON object.
0129   keys = fieldnames(object);
0130   vals = struct2cell(structfun(@savejsonValue, object, 'UniformOutput', false));
0131   pairs = [keys(:) vals(:)]';
0132   switch size(pairs, 2)
0133     case 0
0134       json = '{}';
0135     case 1
0136       json = ['{' sprintf('"%s":%s', pairs{:}) '}'];
0137     otherwise
0138       json = ['{' ...
0139               sprintf('"%s":%s,', pairs{:, 1:end-1}) ...
0140               sprintf('"%s":%s', pairs{:, end}) ...
0141               '}'];
0142   end
0143 end
0144 
0145 function json = savejsonArray(object)
0146 %SAVEJSONARRAY  Encode a cell array or array as a JSON array.
0147   if iscell(object)
0148     vals = cellfun(@savejsonValue, object, 'UniformOutput', false);
0149   else
0150     vals = arrayfun(@savejsonValue, object, 'UniformOutput', false);
0151   end
0152   switch numel(vals)
0153     case 0
0154       json = '[]';
0155     case 1
0156       json  = ['[' sprintf('%s', vals{:}) ']'];
0157     otherwise
0158       json  = ['[' sprintf('%s,', vals{1:end-1}) sprintf('%s', vals{end}) ']'];
0159   end
0160 end
0161 
0162 function json = savejsonValue(object)
0163 %SAVEJSONVALUE  Encode an arbitrary value as a JSON value.
0164   if ischar(object) && isrow(object)
0165     json = savejsonString(object);
0166   elseif ~isscalar(object) || iscell(object)
0167     json = savejsonArray(object);
0168   elseif islogical(object)
0169     json = savejsonBoolean(object);
0170   elseif isnumeric(object)
0171     json = savejsonNumber(object);
0172   elseif isstruct(object)
0173     json = savejsonObject(object);
0174   end
0175 end
0176 
0177 function json = savejsonBoolean(object)
0178 %SAVEJSONBOOLEAN  Encode a scalar boolean value as a JSON boolean value.
0179   if object
0180     json = 'true';
0181   else
0182     json = 'false';
0183   end
0184 end
0185 
0186 function json = savejsonNumber(object)
0187 %WRTIEJSONNUMBER  Encode a scalar numeric value as a JSON number value.
0188   if isnan(object)
0189     json = 'null';
0190   else
0191     json = sprintf('%G', object);
0192   end
0193 end
0194 
0195 function json = savejsonString(object)
0196 %SAVEJSONSTRING  Encode a row char vector value as a JSON string value.
0197   control_characters = arrayfun(@(b)(native2unicode(b, 'UTF-8')), ...
0198                                 uint8(0:31), 'UniformOutput', false);
0199   control_escapeseqs = arrayfun(@(b)(sprintf('\\u%04x', b)), ...
0200                                 uint8(0:31), 'UniformOutput', false);
0201   control_escapeseqs(1+[8 9 10 12 13])  = {'\b' '\t' '\n' '\f' '\r'};
0202   json = [ ...
0203     '"' ...    
0204     regexprep(object, ...
0205               regexptranslate('escape', [{'\'  '"' } control_characters]), ...
0206               regexptranslate('escape', [{'\\' '\"'} control_escapeseqs])) ...
0207     '"' ];
0208 end

Generated on Fri 06-Oct-2017 10:47:42 by m2html © 2005