Skip to content

Commit

Permalink
[feat] support using \. or [] to escape dots in key names
Browse files Browse the repository at this point in the history
  • Loading branch information
fangq committed Mar 24, 2024
1 parent ee830cd commit 67f30ca
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 13 deletions.
18 changes: 12 additions & 6 deletions jsonpath.m
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
function obj = jsonpath(root, jsonpath)
function obj = jsonpath(root, jpath)
%
% obj=jsonpath(root, jsonpath)
% obj=jsonpath(root, jpath)
%
% Query and retrieve elements from matlab data structures using JSONPath
%
% author: Qianqian Fang (q.fang <at> neu.edu)
%
% input:
% root: a matlab data structure like an array, cell, struct, etc
% jsonpath: a string in the format of JSONPath, see loadjson help
% jpath: a string in the format of JSONPath, see loadjson help
%
% output:
% obj: if the specified element exist, obj returns the result
Expand All @@ -23,9 +23,13 @@
%

obj = root;
jsonpath = regexprep(jsonpath, '([^.\]])(\[[-0-9:\*]+\])', '$1.$2');
jsonpath = regexprep(jsonpath, '\[[''"]*([^\]''"]+)[''"]*\]', '.[$1]');
[pat, paths] = regexp(jsonpath, '(\.{0,2}[^\.]+)', 'match', 'tokens');
jpath = regexprep(jpath, '([^.\]])(\[[-0-9:\*]+\])', '$1.$2');
jpath = regexprep(jpath, '\[[''"]*([^\]''"]+)[''"]*\]', '.[$1]');
jpath = regexprep(jpath, '\\\.', '_0x2E_');
while(regexp(jpath, '(\[[''"]*[^\]''"]+)\.(?=[^\]''"]+[''"]*\])'))
jpath = regexprep(jpath, '(\[[''"]*[^\]''"]+)\.(?=[^\]''"]+[''"]*\])', '$1_0x2E_');
end
[pat, paths] = regexp(jpath, '(\.{0,2}[^\.]+)', 'match', 'tokens');
if (~isempty(pat) && ~isempty(paths))
if (strcmp(paths{1}, '$'))
paths(1) = [];
Expand Down Expand Up @@ -139,6 +143,8 @@
for idx = 1:length(items)
if (isa(input, 'containers.Map'))
[val, isfound] = getonelevel(input(items{idx}), [paths{1:pathid - 1} {['..' pathname]}], pathid);
elseif (length(input) > 1) % struct array
[val, isfound] = getonelevel({input.(items{idx})}, [paths{1:pathid - 1} {['..' pathname]}], pathid);
else
[val, isfound] = getonelevel(input.(items{idx}), [paths{1:pathid - 1} {['..' pathname]}], pathid);
end
Expand Down
18 changes: 11 additions & 7 deletions test/run_jsonlab_test.m
Original file line number Diff line number Diff line change
Expand Up @@ -382,21 +382,25 @@ function run_jsonlab_test(tests)
test_jsonlab('jsonpath use [''*''] and ["*"]', @savejson, jsonpath(testdata, '$["book"][:-2][''author'']'), '["Yoda","Jinn"]', 'compact', 1);
test_jsonlab('jsonpath use combinations', @savejson, jsonpath(testdata, '$..["book"][:-2].author[*][0]'), '["Yoda"]', 'compact', 1);

testdata = struct('book', struct(encodevarname('_title'), {'Minch', 'Qui-Gon', 'Ben'}, encodevarname(' author '), {'Yoda', 'Jinn', 'Kenobi'}), 'game', struct('title', 'Mario'));
test_jsonlab('jsonpath encoded field name in []', @savejson, jsonpath(testdata, '$..["book"][_title][*][0]'), '["Minch"]', 'compact', 1);
test_jsonlab('jsonpath encoded field name after .', @savejson, jsonpath(testdata, '$..["book"]._title[*][0]'), '["Minch"]', 'compact', 1);
test_jsonlab('jsonpath encoded field name after ..', @savejson, jsonpath(testdata, '$.._title'), '["Minch","Qui-Gon","Ben"]', 'compact', 1);
test_jsonlab('jsonpath encoded field name after .', @savejson, jsonpath(testdata, '$..["book"]['' author ''][*][1]'), '["Jinn"]', 'compact', 1);

if (exist('containers.Map'))
testdata = struct('book', containers.Map({'title', 'author'}, {{'Minch', 'Qui-Gon', 'Ben'}, {'Yoda', 'Jinn', 'Kenobi'}}), 'game', struct('title', 'Mario'));
testdata = loadjson(savejson('', testdata), 'usemap', 1);
test_jsonlab('jsonpath use combinations', @savejson, jsonpath(testdata, '$..["book"].author[*][0]'), '["Yoda"]', 'compact', 1);
end
if (exist('istable'))
testdata = struct('book', table({'Minch', 'Qui-Gon', 'Ben'}, {'Yoda', 'Jinn', 'Kenobi'}, 'variablenames', {'title', 'author'}), 'game', struct('title', 'Mario'));
test_jsonlab('jsonpath use combinations', @savejson, jsonpath(testdata, '$..["book"].author[*][0]'), '["Yoda"]', 'compact', 1);
end

testdata = struct('book', struct(encodevarname('_title'), {'Minch', 'Qui-Gon', 'Ben'}, encodevarname(' author.last.name '), {'Yoda', 'Jinn', 'Kenobi'}), encodevarname('game.arcade'), struct('title', 'Mario'));
test_jsonlab('jsonpath encoded field name in []', @savejson, jsonpath(testdata, '$..["book"][_title][*][0]'), '["Minch"]', 'compact', 1);
test_jsonlab('jsonpath encoded field name after .', @savejson, jsonpath(testdata, '$..["book"]._title[*][0]'), '["Minch"]', 'compact', 1);
test_jsonlab('jsonpath encoded field name after ..', @savejson, jsonpath(testdata, '$.._title'), '["Minch","Qui-Gon","Ben"]', 'compact', 1);
test_jsonlab('jsonpath multiple encoded field name between quotes', @savejson, jsonpath(testdata, '$..["book"]['' author.last.name ''][*][1]'), '["Jinn"]', 'compact', 1);
test_jsonlab('jsonpath multiple encoded field name between []', @savejson, jsonpath(testdata, '$..["book"][ author.last.name ][*][1]'), '["Jinn"]', 'compact', 1);
test_jsonlab('jsonpath escape . using \.', @savejson, jsonpath(testdata, '$.game\.arcade'), '{"title":"Mario"}', 'compact', 1);
test_jsonlab('jsonpath escape . using []', @savejson, jsonpath(testdata, '$.[game.arcade]'), '{"title":"Mario"}', 'compact', 1);
test_jsonlab('jsonpath scan struct array', @savejson, jsonpath(testdata, '$.book[*]..author[*]'), '[]', 'compact', 1);

clear testdata;
end

Expand Down

0 comments on commit 67f30ca

Please sign in to comment.