summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2024-04-21 20:15:42 +0000
committerKarl Berry <karl@freefriends.org>2024-04-21 20:15:42 +0000
commit5859acf671790b4510a8af45cdb257f79ae1927b (patch)
tree28a21bf0cf14933dafcb658eaf1950d44468c3eb /Master/texmf-dist/tex
parent3d83a1fdca3cdede368f6ccce91559bdb2c60bbc (diff)
jsonparse (21apr24)
git-svn-id: svn://tug.org/texlive/trunk@71031 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex')
-rw-r--r--Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty513
1 files changed, 315 insertions, 198 deletions
diff --git a/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty b/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty
index a50bafc52de..dc42c7a2291 100644
--- a/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty
+++ b/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty
@@ -5,104 +5,142 @@
% conditions of the LaTeX Project Public License version 1.3c,
% available at http://www.latex-project.org/lppl/.
%
-% This file is part of the `jsonparse' package (The Work in LPPL)
+% This file is part of the `jsonparse' package (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
-% This work has the LPPL maintenance status `author-maintained'.
+% This work has the LPPL maintenance status `maintained'.
%
-\ProvidesExplPackage {jsonparse} {2024-04-11} {0.5.6}
+\ProvidesExplPackage {jsonparse} {2024-04-20} {0.7.1}
{JSON Parse}
-\bool_new:N \l_jsonparse_debug_mode_bool
+\bool_new:N \l__jsonparse_debug_mode_bool
\keys_define:nn { jsonparse } {
- debug .bool_set:N = \l_jsonparse_debug_mode_bool ,
- debug .default:n = { true } ,
+ debug .bool_set:N = \l__jsonparse_debug_mode_bool ,
+ debug .default:n = { true } ,
}
\ProcessKeyOptions [ jsonparse ]
-\msg_new:nnn { jsonparse } { parsing-error } {
- \msg_warning_text:n { jsonparse } \iow_newline:
- Could ~ not ~ parse ~ JSON. \iow_newline:
- Parsing ~ error ~ at ~ key ~ `#1` ~ with ~ value ~ `#2`.
-}
-
\msg_new:nnn { jsonparse } { debug-info } {
#1
}
-% ===
-
-\str_new:N \l_jsonparse_child_sep_str
-\str_set:Nn \l_jsonparse_child_sep_str { . }
-\str_new:N \l_jsonparse_array_sep_left_str
-\str_set:Nn \l_jsonparse_array_sep_left_str { [ }
-\str_new:N \l_jsonparse_array_sep_right_str
-\str_set:Nn \l_jsonparse_array_sep_right_str { ] }
-\str_new:N \l_jsonparse_true_str
-\str_set:Nn \l_jsonparse_true_str { true }
-\str_new:N \l_jsonparse_false_str
-\str_set:Nn \l_jsonparse_false_str { false }
-\str_new:N \l_jsonparse_null_str
-\str_set:Nn \l_jsonparse_null_str { null }
-
-\bool_new:N \l_jsonparse_array_index_zero_based_bool
-\bool_set_true:N \l_jsonparse_array_index_zero_based_bool
-
-\bool_new:N \l_jsonparse_escape_input_bool
-\bool_set_true:N \l_jsonparse_escape_input_bool
-
-\NewDocumentCommand { \JSONParseSetChildSeparator } { m } {
- \str_set:Nn \l_jsonparse_child_sep_str { #1 }
-}
-
-\NewDocumentCommand { \JSONParseSetArraySeparator } { m m } {
- \str_set:Nn \l_jsonparse_array_sep_left_str { #1 }
- \str_set:Nn \l_jsonparse_array_sep_right_str { #2 }
+\msg_new:nnn { jsonparse } { parsing-error } {
+ \msg_error_text:n { jsonparse } \iow_newline:
+ Could ~ not ~ parse ~ JSON. \iow_newline:
+ Parsing ~ error ~ at ~ key ~ `#1` ~ with ~ value ~ `#2`.
}
-\NewDocumentCommand { \JSONParseSetTrueString } { m } {
- \str_set:Nn \l_jsonparse_true_str { #1 }
+\msg_new:nnn { jsonparse } { nested-non-expandable } {
+ \msg_error_text:n { jsonparse } \iow_newline:
+ Nested ~ use ~ of ~ \token_to_str:N \JSONParseValue \c_space_tl not ~ allowed. \iow_newline:
+ Use ~ \token_to_str:N \JSONParseExpandableValue \c_space_tl instead.
}
-\NewDocumentCommand { \JSONParseSetFalseString } { m } {
- \str_set:Nn \l_jsonparse_false_str { #1 }
+\msg_new:nnn { jsonparse } { file-not-found } {
+ \msg_error_text:n { jsonparse } \iow_newline:
+ Could ~ not ~ find ~ file ~ #1.
}
-\NewDocumentCommand { \JSONParseSetNullString } { m } {
- \str_set:Nn \l_jsonparse_null_str { #1 }
+\msg_new:nnn { jsonparse } { escape-in-key } {
+ \msg_error_text:n { jsonparse } \iow_newline:
+ Invalid ~ escape ~ sequence ~ #1 ~ in ~ key.
}
-\NewDocumentCommand { \JSONParseSetArrayIndexZeroBased } { } {
- \bool_set_true:N \l_jsonparse_array_index_zero_based_bool
+% ===
+
+\str_new:N \l__jsonparse_child_sep_str
+\str_new:N \l__jsonparse_array_sep_left_str
+\str_new:N \l__jsonparse_array_sep_right_str
+\str_new:N \l__jsonparse_true_str
+\str_new:N \l__jsonparse_false_str
+\str_new:N \l__jsonparse_null_str
+\bool_new:N \l__jsonparse_array_index_zero_based_bool
+\bool_new:N \l__jsonparse_escape_basic_bool
+\bool_new:N \l__jsonparse_escape_full_bool
+
+\str_new:N \l__jsonparse_backspace_str
+\str_new:N \l__jsonparse_formfeed_str
+\str_new:N \l__jsonparse_linefeed_str
+\str_new:N \l__jsonparse_carriage_return_str
+\str_new:N \l__jsonparse_horizontal_tab_str
+
+\keys_define:nn { jsonparse } {
+ escape .choice: ,
+ escape / false .code:n = {
+ \bool_set_false:N \l__jsonparse_escape_basic_bool
+ \bool_set_false:N \l__jsonparse_escape_full_bool
+ } ,
+ escape / basic .code:n = {
+ \bool_set_true:N \l__jsonparse_escape_basic_bool
+ \bool_set_false:N \l__jsonparse_escape_full_bool
+ } ,
+ escape / full .code:n = {
+ \bool_set_true:N \l__jsonparse_escape_basic_bool
+ \bool_set_true:N \l__jsonparse_escape_full_bool
+ } ,
+ escape .default:n = { basic } ,
+ escape .initial:n = { basic } ,
+ array ~ index ~ zero-based .bool_set:N = \l__jsonparse_array_index_zero_based_bool ,
+ array ~ index ~ zero-based .default:n = { true } ,
+ array ~ index ~ zero-based .initial:n = { true } ,
+ separator .code:n = { \keys_set:nn { jsonparse / separator } {#1} },
+ separator / child .str_set:N = \l__jsonparse_child_sep_str ,
+ separator / child .initial:n = { . } ,
+ separator / array ~ left .str_set:N = \l__jsonparse_array_sep_left_str ,
+ separator / array ~ left .initial:n = { [ } ,
+ separator / array ~ right .str_set:N = \l__jsonparse_array_sep_right_str ,
+ separator / array ~ right .initial:n = { ] } ,
+ replacement .code:n = { \keys_set:nn { jsonparse / replacement } {#1} },
+ replacement / true .str_set:N = \l__jsonparse_true_str ,
+ replacement / true .initial:n = { true } ,
+ replacement / false .str_set:N = \l__jsonparse_false_str ,
+ replacement / false .initial:n = { false } ,
+ replacement / null .str_set:N = \l__jsonparse_null_str ,
+ replacement / null .initial:n = { null } ,
+ replacement / backspace .str_set:N = \l__jsonparse_backspace_str ,
+ replacement / backspace .initial:n = { ~ } ,
+ replacement / formfeed .str_set:N = \l__jsonparse_formfeed_str ,
+ replacement / formfeed .initial:n = { ~ } ,
+ replacement / linefeed .str_set:N = \l__jsonparse_linefeed_str ,
+ replacement / linefeed .initial:n = { ~ } ,
+ replacement / carriage ~ return .str_set:N = \l__jsonparse_carriage_return_str ,
+ replacement / carriage ~ return .initial:n = { ~ } ,
+ replacement / horizontal ~ tab .str_set:N = \l__jsonparse_horizontal_tab_str ,
+ replacement / horizontal ~ tab .initial:n = { ~ }
}
-\NewDocumentCommand { \JSONParseSetArrayIndexOneBased } { } {
- \bool_set_false:N \l_jsonparse_array_index_zero_based_bool
+\NewDocumentCommand { \JSONParseSet } { m } {
+ \keys_set:nn { jsonparse } {#1}
}
% ===
-\cs_generate_variant:Nn \tl_count:n { e }
+\cs_if_exist:NF \str_casefold:n {
+ \cs_new:Npn \str_casefold:n { \str_foldcase:n }
+}
+
\cs_generate_variant:Nn \tl_range:nnn { nne , nen }
\cs_generate_variant:Nn \tl_range:Nnn { Nne , Nen }
-\cs_generate_variant:Nn \tl_remove_once:Nn { Ne }
+\cs_generate_variant:Nn \tl_remove_once:Nn { NV }
+\cs_generate_variant:Nn \tl_replace_all:Nnn { Nen }
\cs_generate_variant:Nn \tl_rescan:nn { ne }
\cs_generate_variant:Nn \tl_set:Nn { Ne }
\cs_generate_variant:Nn \tl_set_rescan:Nnn { Nne }
-\cs_generate_variant:Nn \tl_trim_spaces:n { V }
+\cs_generate_variant:Nn \tl_trim_spaces:n { e }
\cs_generate_variant:Nn \str_case_e:nn { en }
+\cs_generate_variant:Nn \str_casefold:n { e }
\cs_generate_variant:Nn \str_head_ignore_spaces:n { e }
-\cs_generate_variant:Nn \str_set:Nn { Ne }
\cs_generate_variant:Nn \prop_gput:Nnn { Nee }
+\cs_generate_variant:Nn \prop_item:Nn { Ne }
\cs_generate_variant:Nn \prop_put:Nnn { Nee }
-\cs_generate_variant:Nn \seq_use:Nn { Ne }
-\cs_generate_variant:Nn \msg_log:nnn { nno }
+\cs_generate_variant:Nn \msg_error:nnnn { nnee }
+\cs_generate_variant:Nn \msg_log:nnn { nne }
+\prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T }
+\prg_generate_conditional_variant:Nnn \tl_if_head_eq_charcode:nN { eN } { T , TF }
\prg_generate_conditional_variant:Nnn \tl_if_head_is_group:n { e } { TF }
-\prg_generate_conditional_variant:Nnn \str_case:nn { en } { F }
-\prg_generate_conditional_variant:Nnn \str_case_e:nn { en } { F }
-\prg_generate_conditional_variant:Nnn \str_if_eq:nn { ee } { T }
-\prg_generate_conditional_variant:Nnn \str_if_eq:nn { en } { T , TF }
+\prg_generate_conditional_variant:Nnn \tl_if_in:nn { nV } { F }
+\prg_generate_conditional_variant:Nnn \str_if_eq:nn { en , eV } { T }
\prop_new:N \g_jsonparse_entries_prop
\prop_new:N \l__jsonparse_temp_prop
@@ -115,21 +153,33 @@
\tl_new:N \l__jsonparse_val_tl
\tl_new:N \l__jsonparse_object_array_key_tl
\tl_new:N \l__jsonparse_object_array_val_tl
-\tl_new:N \l__jsonparse_array_prefix_tl
\tl_new:N \l__jsonparse_remainder_tl
\int_new:N \l__jsonparse_array_index_int
\int_new:N \l__jsonparse_array_count_int
\int_new:N \l__jsonparse_array_count_last_int
-\bool_new:N \l__prop_map_first_bool
+\bool_new:N \l__jsonparse_prop_map_first_bool
\ior_new:N \l__jsonparse_json_ior
% ===
-\cs_new:Npn \jsonparse_parse_to_prop:Nn #1#2 {
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+\cctab_const:Nn \c__jsonparse_json_escape_cctab {
+ \char_set_catcode_group_begin:n { 123 } % left brace
+ \char_set_catcode_group_end:n { 125 } % right brace
+ \char_set_catcode_other:N b
+ \char_set_catcode_other:N f
+ \char_set_catcode_other:N n
+ \char_set_catcode_other:N r
+ \char_set_catcode_other:N t
+ \char_set_catcode_other:N u
+}
+
+% ===
+
+\cs_new_protected:Npn \jsonparse_parse_to_prop:Nn #1#2 {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
\iow_newline:
Parsing ~ JSON ~ ...
@@ -137,41 +187,38 @@
}
\prop_gclear:N \g_jsonparse_entries_prop
\group_begin:
- \bool_if:NT \l_jsonparse_escape_input_bool {
- \tl_set_eq:NN \par \c_space_tl
- \tl_set:Nn \" { \exp_not:N \" }
- \tl_set:Nn \/ { \exp_not:N \/ }
- \tl_set:Nn \\ { \exp_not:N \\ }
+ \bool_if:NT \l__jsonparse_escape_full_bool {
+ \cs_set:Npn \b { \exp_not:N \b }
+ \cs_set:Npn \f { \exp_not:N \f }
+ \cs_set:Npn \n { \exp_not:N \n }
+ \cs_set:Npn \r { \exp_not:N \r }
+ \cs_set:Npn \t { \exp_not:N \t }
+ \cs_set:Npn \u { \exp_not:N \u }
+ }
+ \bool_if:NT \l__jsonparse_escape_basic_bool {
+ \cs_set:Npn \par { \c_space_tl }
+ \cs_set:Npn \" { \exp_not:N \" }
+ \cs_set:Npn \/ { \exp_not:N \/ }
+ \cs_set:Npn \\ { \exp_not:N \\ }
}
\jsonparse_parse:n {#2}
\group_end:
\prop_set_eq:NN #1 \g_jsonparse_entries_prop
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
JSON ~ parsing ~ done. \iow_newline:
}
}
}
-\cs_new:Npn \jsonparse_parse:n #1 {
+\cs_new_protected:Npn \jsonparse_parse:n #1 {
\tl_set:Ne \l__jsonparse_input_tl { \tl_trim_spaces:n {#1} }
\tl_if_head_is_group:eTF { \l__jsonparse_input_tl } {
\exp_last_unbraced:Ne
\__jsonparse_parse_object:w \l__jsonparse_input_tl \q_stop
} {
- \str_case_e:enF { \str_head_ignore_spaces:e { \l__jsonparse_input_tl } } {
- { [ } {
- \exp_last_unbraced:Ne
- \__jsonparse_parse_array_begin:w \l__jsonparse_input_tl \q_stop
- }
- { ] } {
- \exp_last_unbraced:Ne
- \__jsonparse_parse_array_end:w \l__jsonparse_input_tl \q_stop
- }
- { " } {
- \exp_last_unbraced:Ne
- \__jsonparse_parse_string_key:w \l__jsonparse_input_tl \q_stop
- }
+ \cs_if_exist_use:cTF { __jsonparse_parse_ \str_head_ignore_spaces:e { \l__jsonparse_input_tl } :w } {
+ \l__jsonparse_input_tl \q_stop
} {
% other
\exp_last_unbraced:Ne
@@ -184,34 +231,34 @@
\cs_new:Npn \__jsonparse_parse_object:w #1#2 \q_stop {
\__jsonparse_array_key_set:
- \tl_set:Ne \l__jsonparse_remainder_tl {#2}
+ \tl_set:Nn \l__jsonparse_remainder_tl {#2}
\group_begin:
% object begin
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nnn { jsonparse } { debug-info } {
(obj ~ begin)
}
}
\tl_if_empty:NTF \l__jsonparse_key_tl {
- \tl_set:Ne \l__jsonparse_object_array_key_tl { \l_jsonparse_child_sep_str }
+ \tl_set_eq:NN \l__jsonparse_object_array_key_tl \l__jsonparse_child_sep_str
} {
- \tl_set:Ne \l__jsonparse_object_array_key_tl { \l__jsonparse_key_tl }
- \tl_set:Ne \l__jsonparse_prefix_tl { \l__jsonparse_key_tl \l_jsonparse_child_sep_str }
- \tl_set:Ne \l__jsonparse_val_tl {#1}
+ \tl_set_eq:NN \l__jsonparse_object_array_key_tl \l__jsonparse_key_tl
+ \tl_set:Ne \l__jsonparse_prefix_tl { \l__jsonparse_key_tl \l__jsonparse_child_sep_str }
+ \tl_set:Nn \l__jsonparse_val_tl {#1}
}
- \tl_set:Ne \l__jsonparse_object_array_val_tl { { #1 } }
+ \tl_set:Nn \l__jsonparse_object_array_val_tl { { #1 } }
\exp_args:Ne \jsonparse_parse:n {#1}
\prop_gput:Nee \g_jsonparse_entries_prop
{ \l__jsonparse_object_array_key_tl } { \l__jsonparse_object_array_val_tl }
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
(key) ~ \str_use:N \l__jsonparse_object_array_key_tl : \iow_newline:
\iow_char:N \ \iow_char:N \ (obj) ~ \str_use:N \l__jsonparse_object_array_val_tl
}
}
% object end
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nnn { jsonparse } { debug-info } {
(obj ~ end)
}
}
@@ -219,23 +266,38 @@
\__jsonparse_parse_remainder:
}
+\cs_new:cpn { __jsonparse_parse_ [ :w } #1 \q_stop {
+ \exp_last_unbraced:Ne
+ \__jsonparse_parse_array_begin:w #1 \q_stop
+}
+
+\cs_new:cpn { __jsonparse_parse_ ] :w } #1 \q_stop {
+ \exp_last_unbraced:Ne
+ \__jsonparse_parse_array_end:w #1 \q_stop
+}
+
+\cs_new:cpn { __jsonparse_parse_ " :w } #1 \q_stop {
+ \exp_last_unbraced:Ne
+ \__jsonparse_parse_string_key:w #1 \q_stop
+}
+
\cs_new:Npn \__jsonparse_parse_array_begin:w [ #1 \q_stop {
\__jsonparse_array_key_set:
\group_begin:
- \tl_set:Ne \l__jsonparse_remainder_tl {#1}
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
% array begin
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nnn { jsonparse } { debug-info } {
(arr ~ begin)
}
}
\int_zero:N \l__jsonparse_array_index_int
- \bool_if:NT \l_jsonparse_array_index_zero_based_bool {
+ \bool_if:NT \l__jsonparse_array_index_zero_based_bool {
\int_decr:N \l__jsonparse_array_index_int
}
- \tl_set:Ne \l__jsonparse_object_array_key_tl { \l__jsonparse_key_tl }
+ \tl_set_eq:NN \l__jsonparse_object_array_key_tl \l__jsonparse_key_tl
\tl_set:Nn \l__jsonparse_object_array_val_tl { [ #1 }
- \tl_set:Ne \l__jsonparse_prefix_tl { \l__jsonparse_key_tl \l_jsonparse_array_sep_left_str }
+ \tl_set:Ne \l__jsonparse_prefix_tl { \l__jsonparse_key_tl \l__jsonparse_array_sep_left_str }
\__jsonparse_parse_remainder:
}
@@ -243,23 +305,23 @@
\tl_set:Ne \l__jsonparse_object_array_val_tl {
\tl_range:Nne \l__jsonparse_object_array_val_tl { 1 } {
\int_eval:n {
- -1 * \tl_count:e {#1} - 1
+ -1 * \tl_count:n {#1} - 1
}
}
}
\prop_gput:Nee \g_jsonparse_entries_prop
{ \l__jsonparse_object_array_key_tl } { \l__jsonparse_object_array_val_tl }
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
(key) ~ \str_use:N \l__jsonparse_object_array_key_tl : \iow_newline:
\iow_char:N \ \iow_char:N \ (arr) ~ \str_use:N \l__jsonparse_object_array_val_tl
}
}
\group_end:
- \tl_set:Ne \l__jsonparse_remainder_tl {#1}
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
% array end
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nnn { jsonparse } { debug-info } {
(arr ~ end)
}
}
@@ -267,32 +329,64 @@
}
\cs_new:Npn \__jsonparse_array_key_set: {
- \str_if_eq:eeT { \tl_item:Nn \l__jsonparse_prefix_tl { -1 } }
- { \l_jsonparse_array_sep_left_str } {
+ \str_if_eq:eVT {
+ \tl_range:Nen \l__jsonparse_prefix_tl {
+ \int_eval:n {
+ -1 * \tl_count:N \l__jsonparse_array_sep_left_str
+ }
+ } { -1 }
+ } \l__jsonparse_array_sep_left_str {
\int_incr:N \l__jsonparse_array_index_int
\tl_set:Ne \l__jsonparse_key_tl {
- \l__jsonparse_prefix_tl \int_use:N \l__jsonparse_array_index_int \l_jsonparse_array_sep_right_str
+ \l__jsonparse_prefix_tl \int_use:N \l__jsonparse_array_index_int \l__jsonparse_array_sep_right_str
}
}
}
\cs_new:Npn \__jsonparse_parse_string_key:w " #1 " #2 \q_stop {
\__jsonparse_array_key_set:
- \tl_set:Ne \l__jsonparse_remainder_tl {#2}
+ \tl_set:Ne \l__jsonparse_remainder_tl { \tl_trim_spaces:n {#2} }
% key or string?
- \str_if_eq:enTF { \tl_head:n { #2 } } { : } {
- \tl_remove_once:Ne \l__jsonparse_remainder_tl { \c_colon_str }
+ \tl_if_head_eq_charcode:eNTF { \l__jsonparse_remainder_tl } : {
+ \tl_remove_once:NV \l__jsonparse_remainder_tl \c_colon_str
+ \bool_if:NT \l__jsonparse_escape_full_bool {
+ \clist_map_inline:nn { \b , \f , \n , \r , \t , \u } {
+ \tl_if_in:nnT {#1} {##1} {
+ \msg_error:nne { jsonparse } { escape-in-key } {
+ \token_to_str:N ##1
+ }
+ }
+ }
+ }
\tl_set:Ne \l__jsonparse_key_tl { \l__jsonparse_prefix_tl #1 }
} {
\group_begin:
- \tl_set:Nn \" { " }
- \tl_set:Nn \/ { / }
- \tl_set:Nn \\ { \c_backslash_str }
- \tl_set:Ne \l__jsonparse_val_tl {#1}
+ \bool_if:NT \l__jsonparse_escape_full_bool {
+ \cs_set:Npn \b { \l__jsonparse_backspace_str }
+ \cs_set:Npn \f { \l__jsonparse_formfeed_str }
+ \cs_set:Npn \n { \l__jsonparse_linefeed_str }
+ \cs_set:Npn \r { \l__jsonparse_carriage_return_str }
+ \cs_set:Npn \t { \l__jsonparse_horizontal_tab_str }
+ \cs_set:Npn \u { \char" }
+ }
+ \bool_if:NT \l__jsonparse_escape_basic_bool {
+ \cs_set:Npn \" { " }
+ \cs_set:Npn \/ { / }
+ \cs_set:Npn \\ { \c_backslash_str }
+ }
+ \tl_set:Nn \l__jsonparse_val_tl {#1}
+ \bool_if:NT \l__jsonparse_escape_full_bool {
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 98 } { 12 } } { b }
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 102 } { 12 } } { f }
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 110 } { 12 } } { n }
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 114 } { 12 } } { r }
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 116 } { 12 } } { t }
+ \tl_replace_all:Nen \l__jsonparse_val_tl { \char_generate:nn { 117 } { 12 } } { u }
+ }
\prop_gput:Nee \g_jsonparse_entries_prop
{ \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
% string
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
(key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
\iow_char:N \ \iow_char:N \ (str) ~ \str_use:N \l__jsonparse_val_tl
@@ -305,71 +399,26 @@
\cs_new:Npn \__jsonparse_parse_other:w #1 \q_stop {
\__jsonparse_array_key_set:
- \tl_set:Ne \l__jsonparse_remainder_tl {#1}
- \tl_set:Ne \l__jsonparse_temp_tl { #1 , }
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
+ \tl_set:Nn \l__jsonparse_temp_tl { #1 , }
\tl_replace_once:Nnn \l__jsonparse_temp_tl { ] } { , }
\exp_last_unbraced:Ne
\__jsonparse_parse_other_aux:w \l__jsonparse_temp_tl \q_stop
}
\cs_new:Npn \__jsonparse_parse_other_aux:w #1 , #2 \q_stop {
- \tl_set:Ne \l__jsonparse_temp_tl {#1}
- \str_case:enF {
- \str_lowercase:f { \l__jsonparse_temp_tl }
- } {
- { true } {
- \tl_set:Ne \l__jsonparse_val_tl {
- \l_jsonparse_true_str
- }
- \prop_gput:Nee \g_jsonparse_entries_prop
- { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
- % true
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
- (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
- \iow_char:N \ \iow_char:N \ (tru) ~ \str_use:N \l__jsonparse_val_tl
- }
- }
- }
- { false } {
- \tl_set:Ne \l__jsonparse_val_tl {
- \l_jsonparse_false_str
- }
- \prop_gput:Nee \g_jsonparse_entries_prop
- { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
- % false
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
- (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
- \iow_char:N \ \iow_char:N \ (fal) ~ \str_use:N \l__jsonparse_val_tl
- }
- }
- }
- { null } {
- \tl_set:Ne \l__jsonparse_val_tl {
- \l_jsonparse_null_str
- }
- \prop_gput:Nee \g_jsonparse_entries_prop
- { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
- % null
- \bool_if:NT \l_jsonparse_debug_mode_bool {
- \msg_log:nne { jsonparse } { debug-info } {
- (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
- \iow_char:N \ \iow_char:N \ (nul) ~ \str_use:N \l__jsonparse_val_tl
- }
- }
- }
- } {
- \fp_compare:nNnTF {#1} ? { 0 } {
+ \tl_set:Nn \l__jsonparse_temp_tl {#1}
+ \cs_if_exist_use:cF { __jsonparse_parse_ \str_casefold:e { \l__jsonparse_temp_tl } : } {
+ \fp_if_nan:nTF {#1} {
% nan
\msg_error:nnee { jsonparse } { parsing-error }
{ \l__jsonparse_key_tl } {#1}
} {
- \tl_set:Ne \l__jsonparse_val_tl {#1}
+ \tl_set:Nn \l__jsonparse_val_tl {#1}
\prop_gput:Nee \g_jsonparse_entries_prop
{ \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
% number
- \bool_if:NT \l_jsonparse_debug_mode_bool {
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
(key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
\iow_char:N \ \iow_char:N \ (num) ~ \str_use:N \l__jsonparse_val_tl
@@ -377,20 +426,59 @@
}
}
}
- \tl_set:Ne \l__jsonparse_remainder_tl { \tl_trim_spaces:V \l__jsonparse_remainder_tl }
+ \tl_set:Ne \l__jsonparse_remainder_tl { \tl_trim_spaces:e { \l__jsonparse_remainder_tl } }
\tl_set:Ne \l__jsonparse_remainder_tl {
\tl_range:Nen \l__jsonparse_remainder_tl {
\int_eval:n {
- \tl_count:e { #1 } + 1
+ \tl_count:n {#1} + 1
}
} { -1 }
}
\__jsonparse_parse_remainder:
}
+\cs_new:Npn \__jsonparse_parse_true: {
+ \tl_set_eq:NN \l__jsonparse_val_tl \l__jsonparse_true_str
+ \prop_gput:Nee \g_jsonparse_entries_prop
+ { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
+ % true
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nne { jsonparse } { debug-info } {
+ (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
+ \iow_char:N \ \iow_char:N \ (tru) ~ \str_use:N \l__jsonparse_val_tl
+ }
+ }
+}
+
+\cs_new:Npn \__jsonparse_parse_false: {
+ \tl_set_eq:NN \l__jsonparse_val_tl \l__jsonparse_false_str
+ \prop_gput:Nee \g_jsonparse_entries_prop
+ { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
+ % false
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nne { jsonparse } { debug-info } {
+ (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
+ \iow_char:N \ \iow_char:N \ (fal) ~ \str_use:N \l__jsonparse_val_tl
+ }
+ }
+}
+
+\cs_new:Npn \__jsonparse_parse_null: {
+ \tl_set_eq:NN \l__jsonparse_val_tl \l__jsonparse_null_str
+ \prop_gput:Nee \g_jsonparse_entries_prop
+ { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
+ % null
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nne { jsonparse } { debug-info } {
+ (key) ~ \str_use:N \l__jsonparse_key_tl : \iow_newline:
+ \iow_char:N \ \iow_char:N \ (nul) ~ \str_use:N \l__jsonparse_val_tl
+ }
+ }
+}
+
\cs_new:Npn \__jsonparse_parse_remainder: {
- \tl_set:Ne \l__jsonparse_remainder_tl { \tl_trim_spaces:V \l__jsonparse_remainder_tl }
- \str_if_eq:enT { \tl_head:N \l__jsonparse_remainder_tl } { , } {
+ \tl_set:Ne \l__jsonparse_remainder_tl { \tl_trim_spaces:e { \l__jsonparse_remainder_tl } }
+ \tl_if_head_eq_charcode:eNT { \l__jsonparse_remainder_tl } , {
\tl_remove_once:Nn \l__jsonparse_remainder_tl { , }
}
\tl_if_empty:NF \l__jsonparse_remainder_tl {
@@ -398,18 +486,19 @@
}
}
-\cs_new:Npn \jsonparse_filter:Nn #1#2 {
+\cs_new_protected:Npn \jsonparse_filter:Nn #1#2 {
+ \prop_clear:N \l__jsonparse_temp_prop
\prop_map_inline:Nn #1 {
\str_case_e:en {
- \tl_range:nne {##1} { 1 } { \int_eval:n { \tl_count:e {#2} + 1 } }
+ \tl_range:nne {##1} { 1 } { \int_eval:n { \tl_count:n {#2} + 1 } }
} {
- { #2 \l_jsonparse_child_sep_str } {
+ { #2 \l__jsonparse_child_sep_str } {
\prop_put:Nee \l__jsonparse_temp_prop
- { \tl_range:nen {##1} { \int_eval:n { \tl_count:e {#2} + 2 } } { -1 } } {##2}
+ { \tl_range:nen {##1} { \int_eval:n { \tl_count:n {#2} + 2 } } { -1 } } {##2}
}
- { #2 \l_jsonparse_array_sep_left_str } {
+ { #2 \l__jsonparse_array_sep_left_str } {
\prop_put:Nee \l__jsonparse_temp_prop
- { \tl_range:nen {##1} { \int_eval:n { \tl_count:e {#2} + 1 } } { -1 } } {##2}
+ { \tl_range:nen {##1} { \int_eval:n { \tl_count:n {#2} + 1 } } { -1 } } {##2}
}
}
}
@@ -418,43 +507,71 @@
% ===
-\NewExpandableDocumentCommand { \JSONParse } { m +m } {
+\NewDocumentCommand { \JSONParse } { m +m } {
+ \tl_if_eq:enT { \tl_head:n {#2} } { \JSONParseValue } {
+ \msg_error:nn { jsonparse } { nested-non-expandable }
+ }
\prop_new:N #1
\jsonparse_parse_to_prop:Nn #1 {#2}
}
-\NewExpandableDocumentCommand { \JSONParseFromFile } { m m } {
- \ior_open:Nn \l__jsonparse_json_ior {#2}
-
+\NewDocumentCommand { \JSONParseFromFile } { m m } {
+ \file_if_exist:nF {#2} {
+ \msg_error:nnn { jsonparse } { file-not-found }
+ {#2}
+ }
\tl_clear:N \l__jsonparse_json_tl
- \ior_map_inline:Nn \l__jsonparse_json_ior {
- \tl_put_right:Nn \l__jsonparse_json_tl {##1}
+ \bool_if:NTF \l__jsonparse_escape_full_bool {
+ \file_get:nnN {#2} { \cctab_select:N \c__jsonparse_json_escape_cctab } \l__jsonparse_json_tl
+ } {
+ \file_get:nnN {#2} { } \l__jsonparse_json_tl
}
-
- \ior_close:N \l__jsonparse_json_ior
-
\prop_new:N #1
\jsonparse_parse_to_prop:Nn #1 { \l__jsonparse_json_tl }
}
-\NewExpandableDocumentCommand { \JSONParseGetValue } { s m m } {
+\NewExpandableDocumentCommand { \JSONParseExpandableValue } { m m } {
+ \prop_item:Ne #1 {#2}
+}
+
+\NewDocumentCommand { \JSONParseValue } { s m m } {
\bool_if:NTF #1 {
- \tl_rescan:ne { } { \prop_item:Nn #2 {#3} }
+ \tl_rescan:ne { } { \prop_item:Ne #2 {#3} }
} {
- \prop_item:Nn #2 {#3}
+ \prop_item:Ne #2 {#3}
+ }
+}
+
+\NewDocumentCommand { \JSONParseKeys } { m m } {
+ \tl_if_exist:NF #2 {
+ \tl_new:N #2
}
+ \bool_set_true:N \l__jsonparse_prop_map_first_bool
+ \tl_set:Nn \l__jsonparse_temp_tl { [ }
+ \prop_map_inline:Nn #1 {
+ \tl_if_in:nVF {##1} \l__jsonparse_child_sep_str {
+ \bool_if:NTF \l__jsonparse_prop_map_first_bool {
+ \bool_set_false:N \l__jsonparse_prop_map_first_bool
+ } {
+ \tl_put_right:Nn \l__jsonparse_temp_tl { , }
+ }
+ \tl_put_right:Nn \l__jsonparse_temp_tl { " ##1 " }
+ }
+ }
+ \tl_put_right:Nn \l__jsonparse_temp_tl { ] }
+ \tl_set_eq:NN #2 \l__jsonparse_temp_tl
}
-\NewExpandableDocumentCommand { \JSONParseGetArrayValues } { s m m O{} m } {
+\NewDocumentCommand { \JSONParseArrayValues } { s m m O{} m } {
\group_begin:
\jsonparse_filter:Nn #2 {#3}
- \bool_set_true:N \l__prop_map_first_bool
+ \bool_set_true:N \l__jsonparse_prop_map_first_bool
\prop_map_inline:Nn #2 {
\str_if_eq:enT {
\tl_range:nen {##1} { \int_eval:n { -1 * \tl_count:n {#4} } } { -1 }
} {#4} {
- \bool_if:NTF \l__prop_map_first_bool {
- \bool_set_false:N \l__prop_map_first_bool
+ \bool_if:NTF \l__jsonparse_prop_map_first_bool {
+ \bool_set_false:N \l__jsonparse_prop_map_first_bool
} {
#5
}
@@ -472,7 +589,7 @@
#1
}
-\NewExpandableDocumentCommand { \JSONParseGetArrayCount } { m m } {
+\NewDocumentCommand { \JSONParseArrayCount } { m m } {
\group_begin:
\jsonparse_filter:Nn #1 {#2}
\int_zero:N \l__jsonparse_array_count_int
@@ -491,7 +608,7 @@
\group_end:
}
-\NewExpandableDocumentCommand { \JSONParseUseArrayValues } { s m m O{} m } {
+\NewDocumentCommand { \JSONParseArrayValuesMap } { s m m O{} m } {
\group_begin:
\jsonparse_filter:Nn #2 {#3}
\prop_map_inline:Nn #2 {
@@ -500,7 +617,7 @@
} {#4} {
\int_incr:N \l__jsonparse_array_index_int
\tl_set:Ne \JSONParseArrayIndex { \__jsonparse_get_array_index:w ##1 \q_stop }
- \tl_set:Ne \JSONParseArrayKey { ##1 }
+ \tl_set:Ne \JSONParseArrayKey {##1}
\bool_if:NTF #1 {
\tl_set_rescan:Nne \JSONParseArrayValue { } { \prop_item:Nn #2 {##1} }
} {