texlive[71065] Master/texmf-dist: jsonparse (24apr24)
commits+karl at tug.org
commits+karl at tug.org
Wed Apr 24 22:20:30 CEST 2024
Revision: 71065
https://tug.org/svn/texlive?view=revision&revision=71065
Author: karl
Date: 2024-04-24 22:20:30 +0200 (Wed, 24 Apr 2024)
Log Message:
-----------
jsonparse (24apr24)
Modified Paths:
--------------
trunk/Master/texmf-dist/doc/latex/jsonparse/README.md
trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.pdf
trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.tex
trunk/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty
Modified: trunk/Master/texmf-dist/doc/latex/jsonparse/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/jsonparse/README.md 2024-04-24 20:20:23 UTC (rev 71064)
+++ trunk/Master/texmf-dist/doc/latex/jsonparse/README.md 2024-04-24 20:20:30 UTC (rev 71065)
@@ -1,10 +1,10 @@
-![Version 0.7.1](https://img.shields.io/badge/version-0.7.1-blue)
+![Version 0.8.0](https://img.shields.io/badge/version-0.8.0-blue)
# The `jsonparse` package
The `jsonparse` package provides a handy way to read in JSON data from files or strings in LaTeX documents, parse the data and store it in a user-defined token variable. The package allows accessing the stored data via a JavaScript-flavored syntax.
-Using the commands `\JSONParseFromFile` or `\JSONParse`, JSON data can be stored in a token variable. Using the command `\JSONParseValue`, certain entried can be extracted from the stored data.
+Using the commands `\JSONParseFromFile` or `\JSONParse`, JSON data can be stored in a token variable. Using the command `\JSONParseValue`, entries can be extracted from the stored data.
---
@@ -43,3 +43,5 @@
We can store it in the token variable `\myJSONdata` using the command `\JSONParseFromFile{\myJSONdata}{example.json}`. Calling the command `\JSONParseValue{\myJSONdata}{contactPoint[0].telephone}` would then result in the output `+1 (555) 555-1234` (indices are zero-based per default).
This package including all files is subject to the LPPL 1.3c license.
+Copyright 2024 Jasper Habicht (mail(at)jasperhabicht.de).
+
Modified: trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.tex 2024-04-24 20:20:23 UTC (rev 71064)
+++ trunk/Master/texmf-dist/doc/latex/jsonparse/jsonparse-doc.tex 2024-04-24 20:20:30 UTC (rev 71065)
@@ -1,5 +1,5 @@
% File: jsonparse-doc.tex
-% Copyright 2024 Jasper Habicht (mail at jasperhabicht.de).
+% Copyright 2024 Jasper Habicht (mail(at)jasperhabicht.de).
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License version 1.3c,
@@ -11,8 +11,8 @@
% This work has the LPPL maintenance status `maintained'.
%
\documentclass[a4paper]{article}
-\def\jsonparsefileversion{0.7.1}
-\def\jsonparsefiledate{20 April 2024}
+\def\jsonparsefileversion{0.8.0}
+\def\jsonparsefiledate{24 April 2024}
\usepackage[T1]{fontenc}
\usepackage{Alegreya}
@@ -194,6 +194,7 @@
\changes{v0.6.0}{2024/04/15}{Bug fixes, renaming of several commands.}
\changes{v0.7.0}{2024/04/18}{Renaming and rearranging of keys, escaping of special JSON escape sequences added.}
\changes{v0.7.1}{2024/04/20}{Access to first-level keys of object added.}
+\changes{v0.8.0}{2024/04/24}{Internal rewrite, escaping procedures changed.}
\begin{document}
@@ -220,26 +221,31 @@
\section{Escaping and special treatment of the input}\label{sec:escaping}
-\begin{macrodef}
-|escape|={<choice>}
-\end{macrodef}
+In general, the package reads the JSON source as string, which means that all characters have category code 12 (other), except for spaces which have category code 10 (space). The \macro{\endlinechar} value is set to $-1$. Furthermore, if PDFLaTeX is used, the upper-half of the 8-bit range is set to ``active''. JSON, however, defines a small set of escape sequences and in order to be able to process these, the category code of the backslash is set to 0 (escpape).
-In general, characters in the JSON source that are special to TeX are not handled in a special way and will be treated by TeX the same way as if the user had input them in the document. However, certain escaping procedures are available to conform with the way JSON treats certain escape sequences.
+JSON strings cannot contain the two characters \macro{"} and \macro{\}. These two characters need to be escaped with a preceding backslash (\macro{\}). This package therefore redefines locally the TeX control symbols \macro{\"}, \macro{\/}, \macro{\\}, \macro{\b}, \macro{\f}, \macro{\n}, \macro{\r}, \macro{\t} and \macro{\u}. These control symbols are prevented from expanding during parsing. For example, \macro{\"} is first defined as \macro{\exp_not:N \"} and only hen typeset, \macro{\"} is expanded to \macro{"}, which ensures that strings are parsed properly.
-The key \macro{escape} takes one of the values \macro{false}, \macro{basic} or \macro{full}. If no value is given, \macro{basic} is assumed and \macro{basic} is also the default setting if the key is not set at all. See more on setting keys below in section \ref{sec:settings}. The three values select different escape modes that are designed to have as little influence as possible to how TeX normally acts. While it would surely be possible to parse and rescan the input by changing category codes and rescanning the output per default, such practice might result un unintended output in special cases. Therefore, the current approach was chosen where changes to category codes are only introduced with the most most extensive escaping mode and rescanning of token sequences can be controlled by the user.
+Similarly, the control symbol \macro{\/} expands eventually to \macro{/} and \macro{\\} to \macro{\c_backslash_str} (i.\,e. a backslash with category code 12). The escape sequence \macro{\u} followed by a hex value consisting of four digits eventually eventually expands to \macro{\char"} followed by the relevant four hex digits. The JSON escape sequences \macro{\b}, \macro{\f}, \macro{\n}, \macro{\r}, \macro{\t} or \macro{\u} (followed by a hex value) eventually expand to token variables of which the contents can be set using the relevant \macro{replacement} key. See more on setting keys below in section \ref{sec:settings}.
-Setting the key to \macro{false} disables the treatment of the input as described in the following of this section. The source code will be read and parsed as is. If the source does not contain any escape sequences, empty lines or TeX macro, this choice should be used.
+It is possible to insert TeX macros to the JSON source that will eventually be parsed when typesetting. Backslashes of TeX macros need to be escaped by another backslash. The TeX macros \macro{\"} and \macro{\\} must be escaped twice in the JSON source, so that they become \macro{\\\"} and \macro{\\\\} respectively.
-If the key \macro{escape} is set to \macro{basic}, the package allows for empty lines in JSON strings. During parsing, every instance of the TeX macro \macro{\par} is replaced by a space.
+\begin{macrodef}
+|\x|[<token variable name>][<key>]
+\end{macrodef}
+Using the control sequence \macro{\x}, it is possible to nest JSON strings into each other. The control sequence takes two arguments delimited by square brackets. The first argument represents the name of the token variable that holds the parsed JSON data where the inserted JSON string should be taken from. The second argument sets the key that should be selected. The following example shows a simple use case:
-JSON strings cannot contain the two characters \macro{"} and \macro{\}. These two characters need to be escaped with a preceding backslash (\macro{\}). If the key \macro{escape} is set to \macro{basic}, this package therefore redefines locally the TeX control symbols \macro{\"}, \macro{\/} and \macro{\\}. During parsing, \macro{\"} expands to \macro{\exp_not:N \"} (i.\,e. it is prevented to expand during parsing) and only when typeset, \macro{\"} is expanded to \macro{"}, which ensures that strings are parsed properly. Similarly, the control symbol \macro{\/} expands to \macro{\exp_not:N \/} and finally to \macro{/} while \macro{\\} expands to \macro{\exp_not:N \\} and finally to \macro{\c_backslash_str} (i.\,e. a backslash with category code 12). Due to this procedure, the TeX macros \macro{\"} and \macro{\\} must be escaped twice in the JSON source, so that they become \macro{\\\"} and \macro{\\\\} respectively.
+\begin{codeexamplecolumns}
+ \JSONParse{\myJSONdataA}{
+ { "a" : { "b" : "c" } }
+ }
-With the key \macro{escape} set to \macro{basic}, other escape sequences defined by JSON, such as \macro{\b}, \macro{\f}, \macro{\n}, \macro{\r}, \macro{\t} or \macro{\u} (the latter followed by a hex value) are not escaped.
+ \JSONParse{\myJSONdataB}{
+ { "d" : \x[myJSONdataA][a] }
+ }
-If the key \macro{escape} is set to \macro{full}, apart from the above, the JSON escape sequences \macro{\b}, \macro{\f}, \macro{\n}, \macro{\r}, \macro{\t} or \macro{\u} (followed by a hex value) are parsed if the JSON source is read in as file using \macro{\JSONParseFromFile} (in other words, full escaping functionality is not supported for the command \macro{\JSONParse}). During parsing, these escape sequences are not expanded and only when being typeset expand to their relevant replacement. The escape sequence \macro{\u} followed by a hex value consisting of four digits eventually expands to \macro{\char"} followed by the relevant four hex digits. The escape sequences \macro{\b} (backspace), \macro{\f} (formfeed), \macro{\n} (linefeed), \macro{\r} (carriage return) and \macro{\t} (horizontal tab) expand to token variables of which the contents can be set using the relevant \macro{replacement} key. See more on setting keys below in section \ref{sec:settings}.
+ \JSONParseValue{\myJSONdataB}{d.b}
+\end{codeexamplecolumns}
-Note that if the key \macro{escape} is set to \macro{full}, the category code of \macro{b}, \macro{f}, \macro{n}, \macro{r}, \macro{t} and \macro{u} will be set to 12 (other). Changing the category codes is necessary to be able to define single-letter control sequences in TeX. The category codes of these characters are changed back to 10 (letter) when stored in the property list that contains the parsed JSON string.
-
\begin{macrodef}
replacement/|backspace|={<string>}
replacement/|formfeed|={<string>}
@@ -281,11 +287,11 @@
Nested objects and arrays are assigned keys that adhere to JavaScript syntax. For example, if the JSON string \macro{{ "outer_key" : { "inner_key" : "value" } }} is parsed into the token variable \macro{\myJSONdata}, to select the value associated with the key \macro{inner_key}, the command \macro{\JSONParseValue{\myJSONdata}{outer_key.inner_key}} can be used. To give an example for an array, the command \macro{\JSONParseValue{\myJSONdata}{key[0]}} selects the first value of the array associated with the key \macro{key} in the JSON string \macro{{ "key" : [ "one" , "two" ] }}.
-The starred variant, \macro{\JSONParseValue*}, rescans the token list before it is typeset (which means that all category codes that may have been changed before are set to the default values), making it possible to place TeX commands in the JSON file. The starred variants of this and similar commands should not be placed in a \macro{\JSONParse} command. In order to adhere to proper JSON syntax, backslashes need to be escaped in the JSON source with another backslash.
+The non-starred variant of this command, \macro{\JSONParseValue}, rescans the token list before it is typeset (which means that all category codes that may have been changed before are set to the default values). The starred variant, \macro{\JSONParseValue*}, does not rescan the ouput. The non-starred variants of this and similar commands should therefore not be placed in a \macro{\JSONParse} command.
When a key is associated with an object or array, the whole object or array is output as JSON string. The special key \macro{.} (or the string defined using the key \macro{child sep}) returns the whole JSON object as string.
-If the output of whole objects or arrays is meant to be parsed again using \macro{\JSONParse}, the expandable command \macro{\JSONParseExpandableValue} is to be used.
+Whole objects or arrays can also be output as JSON string for further use in other macros using the expandable command \macro{\JSONParseExpandableValue}.
\begin{macrodef}
|\JSONParseArrayValues|{<token variable>}{<key>}[<subkey>]{<string>}
@@ -312,7 +318,7 @@
Then, when using \macro{\JSONParseArrayValues{\myJSONdata}{array}[key_a]{, }}, `one, three' is typeset to the document.
-The starred variant, \macro{\JSONParseArrayValues*}, rescans the token lists before they are typeset.
+The starred variant, \macro{\JSONParseArrayValues*}, does not rescan the token lists before they are typeset.
\begin{macrodef}
|\JSONParseArrayValuesMap|{<token variable>}{<key>}[<subkey>]{<command name>}
@@ -335,7 +341,7 @@
\end{itemize}
\end{codeexamplecolumns}
-The starred variant, \macro{\JSONParseArrayValuesMap*}, rescans the token lists before they are typeset.
+The starred variant, \macro{\JSONParseArrayValuesMap*}, does not rescan the token lists before they are typeset.
\begin{macrodef}
|\JSONParseArrayCount|{<token variable>}{<key>}
Modified: trunk/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty 2024-04-24 20:20:23 UTC (rev 71064)
+++ trunk/Master/texmf-dist/tex/latex/jsonparse/jsonparse.sty 2024-04-24 20:20:30 UTC (rev 71065)
@@ -1,5 +1,5 @@
% File: jsonparse.sty
-% Copyright 2024 Jasper Habicht (mail at jasperhabicht.de).
+% Copyright 2024 Jasper Habicht (mail(at)jasperhabicht.de).
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License version 1.3c,
@@ -10,7 +10,7 @@
%
% This work has the LPPL maintenance status `maintained'.
%
-\ProvidesExplPackage {jsonparse} {2024-04-20} {0.7.1}
+\ProvidesExplPackage {jsonparse} {2024-04-24} {0.8.0}
{JSON Parse}
\bool_new:N \l__jsonparse_debug_mode_bool
@@ -55,8 +55,6 @@
\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
@@ -65,21 +63,6 @@
\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 } ,
@@ -119,33 +102,31 @@
\cs_new:Npn \str_casefold:n { \str_foldcase:n }
}
+\cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nne }
\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 { NV }
-\cs_generate_variant:Nn \tl_replace_all:Nnn { Nen }
-\cs_generate_variant:Nn \tl_rescan:nn { ne }
+\cs_generate_variant:Nn \tl_rescan:nn { no , 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 { 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 \prop_gput:Nnn { Nee }
-\cs_generate_variant:Nn \prop_item:Nn { Ne }
-\cs_generate_variant:Nn \prop_put:Nnn { Nee }
+\cs_generate_variant:Nn \prop_item:Nn { Ne , ce }
+\cs_generate_variant:Nn \prop_put:Nnn { Nen , Nee }
\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 \tl_if_in:nn { nV } { F }
-\prg_generate_conditional_variant:Nnn \str_if_eq:nn { en , eV } { T }
+\prg_generate_conditional_variant:Nnn \str_if_eq:nn { en , eV } { T , TF }
\prop_new:N \g_jsonparse_entries_prop
\prop_new:N \l__jsonparse_temp_prop
-\tl_new:N \l__jsonparse_json_tl
+\tl_new:N \g__jsonparse_json_tl
\tl_new:N \l__jsonparse_input_tl
\tl_new:N \l__jsonparse_temp_tl
\tl_new:N \l__jsonparse_prefix_tl
@@ -166,14 +147,11 @@
% ===
\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
+ \cctab_select:N \c_str_cctab
+ \char_set_catcode_escape:n { 92 }
+ \bool_lazy_or:nnF
+ { \sys_if_engine_xetex_p: } { \sys_if_engine_luatex_p: }
+ { \int_step_function:nnN { 128 } { 255 } \char_set_catcode_active:n }
}
% ===
@@ -186,24 +164,8 @@
}
}
\prop_gclear:N \g_jsonparse_entries_prop
- \group_begin:
- \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
+ \jsonparse_parse:n {#2}
+ \prop_gset_eq:NN #1 \g_jsonparse_entries_prop
\bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nne { jsonparse } { debug-info } {
JSON ~ parsing ~ done. \iow_newline:
@@ -213,26 +175,46 @@
\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 } {
+ \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
- \__jsonparse_parse_object: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
- \__jsonparse_parse_other:w \l__jsonparse_input_tl \q_stop
- }
+ \__jsonparse_parse_other:w \l__jsonparse_input_tl \q_stop
}
}
% ===
-\cs_new:Npn \__jsonparse_parse_object:w #1#2 \q_stop {
+\cs_new:cpn { __jsonparse_parse_ \c_left_brace_str :w } #1 \q_stop {
+ \exp_last_unbraced:Ne
+ \__jsonparse_parse_object_begin:w #1 \q_stop
+}
+
+\cs_new:cpn { __jsonparse_parse_ \c_right_brace_str :w } #1 \q_stop {
+ \exp_last_unbraced:Ne
+ \__jsonparse_parse_object_end:w #1 \q_stop
+}
+
+\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
+}
+
+\exp_last_unbraced:NNo \cs_new:Npn \__jsonparse_parse_object_begin:w \c_left_brace_str #1 \q_stop {
\__jsonparse_array_key_set:
- \tl_set:Nn \l__jsonparse_remainder_tl {#2}
\group_begin:
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
% object begin
\bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nnn { jsonparse } { debug-info } {
@@ -244,10 +226,19 @@
} {
\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:Nn \l__jsonparse_object_array_val_tl { { #1 } }
- \exp_args:Ne \jsonparse_parse:n {#1}
+ \tl_set:Nn \l__jsonparse_object_array_val_tl { \c_left_brace_str #1 }
+ \__jsonparse_parse_remainder:
+}
+
+\exp_last_unbraced:NNo \cs_new:Npn \__jsonparse_parse_object_end:w \c_right_brace_str #1 \q_stop {
+ \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: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 {
@@ -256,31 +247,17 @@
\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:nnn { jsonparse } { debug-info } {
- (obj ~ end)
- }
- }
\group_end:
+ % object end
+ \bool_if:NT \l__jsonparse_debug_mode_bool {
+ \msg_log:nnn { jsonparse } { debug-info } {
+ (obj ~ end)
+ }
+ }
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
\__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:
@@ -318,7 +295,6 @@
}
}
\group_end:
- \tl_set:Nn \l__jsonparse_remainder_tl {#1}
% array end
\bool_if:NT \l__jsonparse_debug_mode_bool {
\msg_log:nnn { jsonparse } { debug-info } {
@@ -325,6 +301,7 @@
(arr ~ end)
}
}
+ \tl_set:Nn \l__jsonparse_remainder_tl {#1}
\__jsonparse_parse_remainder:
}
@@ -349,50 +326,18 @@
% key or string?
\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 }
+ } {
+ \tl_set:Nn \l__jsonparse_val_tl {#1}
+ \prop_gput:Nee \g_jsonparse_entries_prop
+ { \l__jsonparse_key_tl } { \l__jsonparse_val_tl }
+ % string
+ \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
+ }
}
- \tl_set:Ne \l__jsonparse_key_tl { \l__jsonparse_prefix_tl #1 }
- } {
- \group_begin:
- \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 {
- \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
- }
- }
- \group_end:
}
\__jsonparse_parse_remainder:
}
@@ -402,12 +347,13 @@
\tl_set:Nn \l__jsonparse_remainder_tl {#1}
\tl_set:Nn \l__jsonparse_temp_tl { #1 , }
\tl_replace_once:Nnn \l__jsonparse_temp_tl { ] } { , }
+ \tl_replace_once:Nen \l__jsonparse_temp_tl { \c_right_brace_str } { , }
\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:Nn \l__jsonparse_temp_tl {#1}
+ \tl_set:Ne \l__jsonparse_temp_tl { \tl_trim_spaces:n {#1} }
\cs_if_exist_use:cF { __jsonparse_parse_ \str_casefold:e { \l__jsonparse_temp_tl } : } {
\fp_if_nan:nTF {#1} {
% nan
@@ -493,11 +439,11 @@
\tl_range:nne {##1} { 1 } { \int_eval:n { \tl_count:n {#2} + 1 } }
} {
{ #2 \l__jsonparse_child_sep_str } {
- \prop_put:Nee \l__jsonparse_temp_prop
+ \prop_put:Nen \l__jsonparse_temp_prop
{ \tl_range:nen {##1} { \int_eval:n { \tl_count:n {#2} + 2 } } { -1 } } {##2}
}
{ #2 \l__jsonparse_array_sep_left_str } {
- \prop_put:Nee \l__jsonparse_temp_prop
+ \prop_put:Nen \l__jsonparse_temp_prop
{ \tl_range:nen {##1} { \int_eval:n { \tl_count:n {#2} + 1 } } { -1 } } {##2}
}
}
@@ -507,12 +453,26 @@
% ===
-\NewDocumentCommand { \JSONParse } { m +m } {
+\NewDocumentCommand { \JSONParse } { m +v } {
\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}
+ \tl_gclear:N \g__jsonparse_json_tl
+ \group_begin:
+ \cs_set:Npn \" { \exp_not:N \" }
+ \cs_set:Npn \/ { \exp_not:N \/ }
+ \cs_set:Npn \\ { \exp_not:N \\ }
+ \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 }
+ \cs_set:Npn \x [ ##1 ] [ ##2 ] { \prop_item:ce {##1} {##2} }
+ \tl_gset_rescan:Nne \g__jsonparse_json_tl { \cctab_select:N \c__jsonparse_json_escape_cctab } {#2}
+ \exp_args:NNe \jsonparse_parse_to_prop:Nn #1 { \g__jsonparse_json_tl }
+ \group_end:
}
\NewDocumentCommand { \JSONParseFromFile } { m m } {
@@ -520,14 +480,22 @@
\msg_error:nnn { jsonparse } { file-not-found }
{#2}
}
- \tl_clear:N \l__jsonparse_json_tl
- \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
- }
\prop_new:N #1
- \jsonparse_parse_to_prop:Nn #1 { \l__jsonparse_json_tl }
+ \tl_gclear:N \g__jsonparse_json_tl
+ \group_begin:
+ \cs_set:Npn \" { \exp_not:N \" }
+ \cs_set:Npn \/ { \exp_not:N \/ }
+ \cs_set:Npn \\ { \exp_not:N \\ }
+ \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 }
+ \cs_set:Npn \x [ ##1 ] [ ##2 ] { \prop_item:ce {##1} {##2} }
+ \file_get:nnN {#2} { \cctab_select:N \c__jsonparse_json_escape_cctab } \g__jsonparse_json_tl
+ \exp_args:NNe \jsonparse_parse_to_prop:Nn #1 { \g__jsonparse_json_tl }
+ \group_end:
}
\NewExpandableDocumentCommand { \JSONParseExpandableValue } { m m } {
@@ -534,11 +502,33 @@
\prop_item:Ne #1 {#2}
}
+\cs_set_eq:NN \__jsonparse_tex_quote \"
+\cs_set_eq:NN \__jsonparse_tex_backslash \\
+
+\cs_new:Npn \__jsonparse_rescan:n #1 {
+ \group_begin:
+ \cs_set:Npn \" { " }
+ \cs_set:Npn \/ { / }
+ \cs_set:Npn \\ { \c_backslash_str }
+ \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" }
+ \tl_set:Ne \l__jsonparse_temp_tl {#1}
+ \tl_analysis_log:N \l__jsonparse_temp_tl
+ \cs_set:Npn \" { \__jsonparse_tex_quote }
+ \cs_set:Npn \\ { \__jsonparse_tex_backslash }
+ \tl_rescan:no { } { \l__jsonparse_temp_tl }
+ \group_end:
+}
+
\NewDocumentCommand { \JSONParseValue } { s m m } {
\bool_if:NTF #1 {
- \tl_rescan:ne { } { \prop_item:Ne #2 {#3} }
+ \prop_item:Ne #2 {#3}
} {
- \prop_item:Ne #2 {#3}
+ \__jsonparse_rescan:n { \prop_item:Ne #2 {#3} }
}
}
@@ -564,9 +554,10 @@
\NewDocumentCommand { \JSONParseArrayValues } { s m m O{} m } {
\group_begin:
- \jsonparse_filter:Nn #2 {#3}
+ \tl_set:Nn \l__jsonparse_temp_tl {#2}
+ \jsonparse_filter:Nn \l__jsonparse_temp_tl {#3}
\bool_set_true:N \l__jsonparse_prop_map_first_bool
- \prop_map_inline:Nn #2 {
+ \prop_map_inline:Nn \l__jsonparse_temp_tl {
\str_if_eq:enT {
\tl_range:nen {##1} { \int_eval:n { -1 * \tl_count:n {#4} } } { -1 }
} {#4} {
@@ -576,9 +567,9 @@
#5
}
\bool_if:NTF #1 {
- \tl_rescan:ne { } {##2}
+ ##2
} {
- ##2
+ \__jsonparse_rescan:n {##2}
}
}
}
@@ -619,9 +610,9 @@
\tl_set:Ne \JSONParseArrayIndex { \__jsonparse_get_array_index:w ##1 \q_stop }
\tl_set:Ne \JSONParseArrayKey {##1}
\bool_if:NTF #1 {
- \tl_set_rescan:Nne \JSONParseArrayValue { } { \prop_item:Nn #2 {##1} }
+ \tl_set:Nn \JSONParseArrayValue { \prop_item:Nn #2 {##1} }
} {
- \tl_set:Ne \JSONParseArrayValue { \prop_item:Nn #2 {##1} }
+ \tl_set:Nn \JSONParseArrayValue { \__jsonparse_rescan:n { \prop_item:Nn #2 {##1} } }
}
\use:c {#5}
}
More information about the tex-live-commits
mailing list.