diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex')
-rw-r--r-- | Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty | 513 |
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} } } { |