@@ -487,6 +487,12 @@ loadjson.m
487487 % request loadjson to store the data in a containers.Map instead of struct (key name limited to 63)
488488 dat=loadjson('{"obj":{"an object with a key longer than 63":"value","array":[1,2,3]}}', 'UseMap', 1)
489489
490+ % loadjson can further download the linked data pointed by _DataLink_ tag, and merge with the parent
491+ dat=loadjson('{"obj":{"_DataLink_":"https://raw.githubusercontent.com/fangq/jsonlab/master/examples/example1.json"},"array":[1,2]}','maxlinklevel',1)
492+
493+ % a JSONPath can be attached to the URL to retrieve a sub element
494+ dat=loadjson('{"obj":{"_DataLink_":"https://raw.githubusercontent.com/fangq/jsonlab/master/examples/example1.json:$.address.city"},"array":[1,2]}','maxlinklevel',1)
495+
490496 % loadjson can optionally return a JSON-memory-map object, which defines each JSON element's
491497 % memory buffer offset and length to enable disk-map like fast read/write operations
492498 [dat, mmap]=loadjson('{"obj":{"key":"value","array":[1,2,3]}}')
@@ -507,6 +513,9 @@ savebj.m
507513 % customizing the root-name using the 1st input, and the 3rd input setting the output file
508514 savebj('rootname',a,'testdata.ubj')
509515
516+ % enabling the 'debug' flag to allow printing binary JSON in text-form, helping users to run tests or troubleshoot
517+ savebj('rootname',a, 'debug',1)
518+
510519 % like savejson, savebj also allow data compression for even more compact storage
511520 savebj('zeros',zeros(100),'Compression','gzip')
512521
@@ -676,6 +685,112 @@ jsonset.m
676685 mmap = loadjson('/path/to/data.json', 'mmaponly', 1);
677686 jsonset('/path/to/data.json', mmap, '$.obj.string', '"new"', '$.obj.array', '[]')
678687
688+ ----------
689+ jsonpath.m
690+ ----------
691+
692+ .. code-block ::
693+
694+ % JSONPath is a widely supported standard to index/search a large struct, such as those loaded from a JSON file
695+ % the jsonpath.m function implements a subset of the features
696+ % the below command returns the value of obj.key subfield, which is "value"
697+ obj = loadjson('{"obj":{"key":"value1","array":[1,2,3],"sub":{"key":"value2","array":[]}}}');
698+ jsonpath(obj, '$.obj.key')
699+
700+ % using [] operator, one can also index array elements, index start from 0; the output below is 2
701+ jsonpath(obj, '$.obj.array[1]')
702+
703+ % [] operator supports range, for example below commands yields [1,2]
704+ jsonpath(obj, '$.obj.array[0:1]')
705+
706+ % a negative index in [] counting elements backwards, -1 means the last element
707+ jsonpath(obj, '$.obj.array[-1]')
708+
709+ % jsonpath.m supports JSONPath's deep-scan operator '..', it traverses through the struct
710+ % and find all keys following .., here the output is {"value1", "value2"}
711+ jsonpath(obj, '$.obj..key')
712+
713+ % you can further concatenate JSONPath operators to select outputs from the earlier ones, this outputs {'value2'}
714+ jsonpath(obj, '$.obj..key[1]')
715+
716+ % instead of .keyname, you can use [keyname], below command is the same as above
717+ jsonpath(obj, '$[obj]..[key][1]')
718+
719+ % one can escape special char, such as ".", in the key using special\.key or [special.key]
720+ jsonpath(obj, '$.obj.special\.key.sub')
721+
722+
723+ -----------
724+ jsoncache.m
725+ -----------
726+
727+ .. code-block ::
728+
729+ % the _DataLink_ annotation in the JData specification permits linking of external data files
730+ % in a JSON file - to make downloading/parsing externally linked data files efficient, such as
731+ % processing large neuroimaging datasets hosted on http://neurojson.io, we have developed a system
732+ % to download files on-demand and cache those locally. jsoncache.m is responsible of searching
733+ % the local cache folders, if found the requested file, it returns the path to the local cache;
734+ % if not found, it returns a SHA-256 hash of the URL as the file name, and the possible cache folders
735+ %
736+ % When loading a file from URL, below is the order of cache file search paths, ranking in search order
737+ %
738+ % global-variable NEUROJSON_CACHE | if defined, this path will be searched first
739+ % [pwd '/.neurojson'] | on all OSes
740+ % /home/USERNAME/.neurojson | on all OSes (per-user)
741+ % /home/USERNAME/.cache/neurojson | if on Linux (per-user)
742+ % /var/cache/neurojson | if on Linux (system wide)
743+ % /home/USERNAME/Library/neurojson| if on MacOS (per-user)
744+ % /Library/neurojson | if on MacOS (system wide)
745+ % C:\ProgramData\neurojson | if on Windows (system wide)
746+ %
747+ % When saving a file from a URL, under the root cache folder, subfolders can be created;
748+ % if the URL is one of a standard NeuroJSON.io URLs as below
749+ %
750+ % https://neurojson.org/io/stat.cgi?action=get&db=DBNAME&doc=DOCNAME&file=sub-01/anat/datafile.nii.gz
751+ % https://neurojson.io:7777/DBNAME/DOCNAME
752+ % https://neurojson.io:7777/DBNAME/DOCNAME/datafile.suffix
753+ %
754+ % the file datafile.nii.gz will be downloaded to /home/USERNAME/.neurojson/io/DBNAME/DOCNAME/sub-01/anat/ folder
755+ % if a URL does not follow the neurojson.io format, the cache folder has the below form
756+ %
757+ % CACHEFOLDER{i}/domainname.com/XX/YY/XXYYZZZZ...
758+ %
759+ % where XXYYZZZZ.. is the SHA-256 hash of the full URL, XX is the first two digit, YY is the 3-4 digits
760+
761+ % below command searches CACHEFOLDER{i}/io/openneuro/ds000001/sub-01/anat/, and return the path/filename
762+ [cachepath, filename] = jsoncache('https://neurojson.org/io/stat.cgi?action=get&db=openneuro&doc=ds000001&file=sub-01/anat/sub-01_inplaneT2.nii.gz&size=669578')
763+
764+ % this searches CACHEFOLDER{i}/raw.githubusercontent.com/55/d2, and the filename is 55d24a4bad6ecc3f5dc4d333be728e01c26b696ef7bc5dd0861b7fa672a28e8e.json
765+ [cachepath, filename] = jsoncache('https://raw.githubusercontent.com/fangq/jsonlab/master/examples/example1.json')
766+
767+ % this searches cachefolder{i}/io/adhd200/Brown folder, and look for file Brown.json
768+ [cachepath, filename] = jsoncache('https://neurojson.io:7777/adhd200/Brown')
769+
770+ % this searches cachefolder{i}/io/openneuro/ds003805 folder, and look for file ds003805.json
771+ [cachepath, filename] = jsoncache('https://neurojson.io:7777/openneuro/ds003805')
772+
773+ -----------
774+ jdlink.m
775+ -----------
776+
777+ .. code-block ::
778+
779+ % jdlink dynamically downloads, caches and parses data files from one or multiple URLs
780+ % jdlink calls jsoncache to scan cache folders first, if a cache copy exists, it loads the cache first
781+
782+ % here we download a dataset from NeuroJSON.io, containing many linked data files
783+ data = loadjson('https://neurojson.io:7777/openneuro/ds000001');
784+
785+ % we now use jsonpath to scan all linked resources under subfolder "anat"
786+ alllinks = jsonpath(data, '$..anat.._DataLink_')
787+
788+ % let's download all linked nifti files (total 4) for sub-01 and sub-02, and load the files as niidata
789+ niidata = jdlink(alllinks, 'regex', 'sub-0[12]_.*\.nii');
790+
791+ % if you just want to download/cache all files and do not want to parse the files, you can run
792+ jdlink(alllinks);
793+
679794---------
680795examples
681796---------
0 commit comments