-
Notifications
You must be signed in to change notification settings - Fork 0
/
jsonparse-doc.tex
579 lines (460 loc) · 35.2 KB
/
jsonparse-doc.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
% File: jsonparse-doc.tex
% 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,
% available at http://www.latex-project.org/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 `maintained'.
%
\documentclass[a4paper]{article}
\def\jsonparsefileversion{0.9.10}
\def\jsonparsefiledate{10 December 2024}
\usepackage[T1]{fontenc}
\usepackage{Alegreya}
\usepackage{AlegreyaSans}
\usepackage{FiraMono}
\usepackage{geometry, longtable, booktabs, siunitx, tcolorbox, hyperref}
\geometry{margin=25mm, left=45mm}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[R]{\thepage}
\linespread{1.1}\selectfont
\addtolength{\skip\footins}{1em plus 5pt}
\makeatletter
\renewcommand*{\thefootnote}{\fnsymbol{footnote}}
\renewcommand{\@makefntext}[1]{%
\noindent\hbox to 0.75em{\normalfont\@thefnmark\hss}~#1%
}
\makeatother
\tcbuselibrary{listings}
\lstdefinestyle{jsonparsedocmacro}{
basicstyle=\small\ttfamily,
literate=*{<}{{{\color{black!50}\guilsinglleft}}}1
{>}{{{\color{black!50}\guilsinglright}}}1,
keywords={},
moredelim=[is][\bfseries]{|}{|},
moredelim=[is][\color{black!50}]{!}{!},
}
\lstdefinestyle{jsonparsedoccodeexample}{
basicstyle=\small\ttfamily,
keywords={},
}
\hypersetup{colorlinks}
\ExplSyntaxOn
\int_new:N \l_jsonparse_doc_change_int
\NewDocumentCommand{\changes}{ m m m }{
\int_incr:N \l_jsonparse_doc_change_int
\prop_new:c { l_jsonparse_doc_change_
\int_to_roman:n { \l_jsonparse_doc_change_int } _prop }
\prop_put:cnn { l_jsonparse_doc_change_
\int_to_roman:n { \l_jsonparse_doc_change_int } _prop } { version } {#1}
\prop_put:cnn { l_jsonparse_doc_change_
\int_to_roman:n { \l_jsonparse_doc_change_int } _prop } { date } {#2}
\prop_put:cnn { l_jsonparse_doc_change_
\int_to_roman:n { \l_jsonparse_doc_change_int } _prop } { changes } {#3}
}
\NewDocumentCommand{\printchanges}{ }{
\section{Changes}
\begin{description}
\int_step_inline:nn { \l_jsonparse_doc_change_int } {
\item[
\prop_item:cn { l_jsonparse_doc_change_
\int_to_roman:n { ##1 } _prop } { version } ]
( \prop_item:cn { l_jsonparse_doc_change_
\int_to_roman:n { ##1 } _prop } { date } ) \\
\prop_item:cn { l_jsonparse_doc_change_
\int_to_roman:n { ##1 } _prop } { changes }
}
\end{description}
}
\tl_new:N \l_jsonparse_doc_doctitle_tl
\NewExpandableDocumentCommand{\makedoctitle}{ o m o m m o m }{
\hypersetup{
pdfauthor={#5},
pdftitle={\IfValueTF{#1}{#1}{#2}},
pdfsubject={\IfValueTF{#3}{#3}{#4}}
}
\tl_set:Nn \l_jsonparse_doc_doctitle_tl {
\group_begin:
\tcbset{
title ~ style ~ hook/.style={
boxrule=2pt,
fontupper=\huge\ttfamily
}
}
\setlength{\parindent}{0pt}\sffamily
\Huge{\bfseries #2}\par\bigskip
\Large #4\par\bigskip
\large #5
\IfValueT{#6}{
\,\footnote{#6}\par\bigskip
}
#7\par\bigskip
\rule{\textwidth}{.08em}
\group_end:
}
}
\NewExpandableDocumentCommand{\printdoctitle}{ }{
\tl_use:N \l_jsonparse_doc_doctitle_tl
}
\ExplSyntaxOff
\tcbset{
size=small,
arc=2.5pt,
outer arc=2.5pt,
colframe=black!10,
colback=black!10,
title style hook/.style={}
}
\NewTCBListing{macrodef}{ }{
listing only,
listing style={jsonparsedocmacro},
grow to left by=2cm,
boxrule=0pt,
after={\par\smallskip\noindent}
}
\NewTCBListing{codeexample}{ }{
listing only,
listing style={jsonparsedoccodeexample},
after={\par\smallskip\noindent}
}
\NewTCBListing{codeexamplecolumns}{ }{
text side listing,
lefthand width=4.5cm,
listing style={jsonparsedoccodeexample},
after={\par\smallskip\noindent}
}
\NewTotalTCBox{\macro}{ O{} v }{
verbatim,
size=tight,
arc=1pt,
outer arc=1pt,
top=0.5pt,
bottom=0.5pt,
left=2pt,
right=2pt,
boxrule=0pt,
colframe=black!10,
colback=black!10,
fontupper=\small\ttfamily,
#1
}{\vphantom{/g}\lstinline^#2^}
\NewTotalTCBox{\titlemacro}{ s O{} m }{
verbatim,
size=tight,
arc=1pt,
outer arc=1pt,
top=0.5pt,
bottom=0.5pt,
left=2pt,
right=2pt,
boxrule=0pt,
colframe=black!10,
colback=black!10,
fontupper=\small\ttfamily,
title style hook,
#2
}{\vphantom{/g}\IfBooleanT{#1}{\textbackslash}#3}
\usepackage{jsonparse}
\makedoctitle
[The jsonparse package]
{The \titlemacro{jsonparse} package}
{A handy way to parse, store and access JSON data from files or strings in LaTeX documents}
{Jasper Habicht}[E-mail: \href{mailto:[email protected]}{[email protected]}. I am grateful to Joseph Wright, Jonathan P. Spratte and David Carlisle who helped me navigating the peculiarities of TeX and optimizing the code. Jason, the JSON parsing horse: Copyright 2024 Hannah Klöber.]
{Version \jsonparsefileversion, released on \jsonparsefiledate}
\changes{v0.3.0}{2024/04/08}{First public beta release.}
\changes{v0.5.0}{2024/04/09}{Changed from string token variables to token lists to support Unicode.}
\changes{v0.5.5}{2024/04/09}{Bug fixes, introduction and enhancement of user functions.}
\changes{v0.5.6}{2024/04/11}{Bug fixes, escaping of special chars added.}
\changes{v0.5.7}{2024/04/14}{Bug fixes, key-value option setting added.}
\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 top-level keys of object added.}
\changes{v0.8.0}{2024/04/24}{Internal rewrite, escaping procedures changed.}
\changes{v0.8.2}{2024/04/26}{Bug fixes, externalizing parsed data.}
\changes{v0.8.3}{2024/04/28}{Escaping of characters with special meaning in TeX.}
\changes{v0.8.5}{2024/05/05}{Enhanced key management.}
\changes{v0.8.6}{2024/05/09}{Bug fix in nesting function.}
\changes{v0.8.7}{2024/08/08}{Corrections in documentation, error messages.}
\changes{v0.9.0}{2024/08/27}{Adaption to updated verbatim tokenization.}
\changes{v0.9.1}{2024/09/21}{Added functions to test for valid JSON numbers.}
\changes{v0.9.3}{2024/10/24}{Fixed a bug that prevented tabs in source from being parsed properly.}
\changes{v0.9.5}{2024/10/27}{Streamlining of code, clarification of explanations in documentation.}
\changes{v0.9.6}{2024/10/31}{Allowing for multiple return values when mapping over arrays.}
\changes{v0.9.7}{2024/11/05}{Streamlining of code, ensuring backward compatibility.}
\changes{v0.9.8}{2024/11/19}{Bug fixes, adding possibility to store value in token list.}
\changes{v0.9.10}{2024/12/10}{Enhanced backward compatibility; switch to linked property lists.}
\begin{document}
\vspace*{-1cm}
\noindent\hspace*{-3.5mm}\includegraphics[width=5cm]{jason/jason.pdf}
\printdoctitle
\bigskip
\section{Introduction}
Hello guys, I am Jason, the JSON parsing horse. JSON data is my favorite thing to parse! But I found that converting JSON to TeX can be a bit tricky. Therefore, I created this package which I am happy to introduce to you.
The \macro{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.
This package is still in a beta stage and not thoroughly tested. Bugs or improvements can be issued via GitHub at \url{https://github.com/jasperhabicht/jsonparse/issues}.
\section{Loading the package}
To install the package, copy the package file \macro{jsonparse.sty} into the working directory or into the \macro{texmf} directory. After the package has been installed, the \macro{jsonparse} package is loaded by calling \macro{\usepackage{jsonparse}} in the preamble of the document.
The package does not load any dependencies.
\begin{macrodef}
|debug|
\end{macrodef}
The package can be loaded with the option \macro{debug}. It will then output to the log file every instance of a string, a boolean (true or false) value, a null value, a number as well as the start and end of every object and the start and end of every array that is found while parsing the JSON string or JSON file.
This key can be set either as package option or using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\section{General remarks of the parsing procedure}
In general, the package will read and store the JSON source and data as string, which means that all characters have category code 12 (``other''), except for spaces and (horizontal) tabs which have category code 10 (``space''). The \macro{\endlinechar} value is set to $-1$ which means that linefeeds and carriage returns are ignored by TeX. These settings are in line with the JSON specification of handling whitespace. Furthermore, if PDFLaTeX is used, the upper-half of the 8-bit range is set to ``active''. Additionally, JSON 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 (``escape'').
\section{Escaping and special treatment of the input}\label{sec:escaping}
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 when typeset, \macro{\"} is expanded to \macro{"}, which ensures that strings are parsed properly.
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 expands to \macro{\char"} followed by the relevant four hex digits. The JSON escape sequences \macro{\b}, \macro{\f}, \macro{\n}, \macro{\r} and \macro{\t} eventually expand to token variables of which the contents can be set using the relevant \macro{replacement} key. See more on setting options below in section \ref{sec:options}.
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.
\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 curly braces. 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:
\begin{codeexamplecolumns}
\JSONParse{\myJSONdataA}{
{ "a" : { "b" : "c" } }
}
\JSONParse{\myJSONdataB}{
{ "d" : \x{myJSONdataA}{a} }
}
\JSONParseValue{\myJSONdataB}{d.b}
\end{codeexamplecolumns}
Note that the control sequence \macro{\x} is replaced by the value exactly. Therefore, if the value happens to be a string, the control sequence \macro{\x} should be placed between quotation marks (\macro{"}) in order for the resulting string to be valid JSON. The control sequence \macro{\x} is only available inside the \macro{\JSONParse} command, but not inside the \macro{\JSONParseFromFile} command.
\begin{macrodef}
|escape|={all}
|escape|={none}
|escape|={number sign}
|escape|={dollar sign}
|escape|={percent sign}
|escape|={ampersand}
|escape|={circumflex accent}
|escape|={low line}
|escape|={tilde}
\end{macrodef}
The key \macro{escape} can be used to convert characters that don't require escaping in JSON but in TeX into the relevant TeX escape sequences. Apart from the backslash and curly braces that need to be escaped anyways, these are the number sign, the dollar sign, the percent sign, the ampersand, the circumflex accent, the low line and the tilde. The characters can be selected individually separated by a comma (for example \macro{escape={dollar sign, circumflex accent, low line}}. With \macro{escape={all}}, all escaping sequences are selected, with \macro{escape={none}}, none is selected.
The naming of the relevant characters follows their Unicode names. However, \macro{hash} exists as alias for \macro{number sign}, \macro{dollar} as alias for \macro{dollar sign}, \macro{percent} for \macro{percent sign}, \macro{circumflex} for \macro{circumflex accent} and \macro{underscore} for \macro{low line}.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParseValue}, \macro{\JSONParseArrayValues} and \macro{\JSONParseArrayValuesMap}.
\begin{macrodef}
|rescan|
|rescan|={<boolean>}
\end{macrodef}
The key \macro{rescan} can be used to activate and deactivate rescanning of the output. This key is active per default. Rescanning converts all tokens to their default category codes and TeX control sequences are expanded before typesetting. Further, during the rescanning process, JSON escape sequences are replaced and characters that don't require escaping in JSON but in TeX are replaced by the relevant TeX escape sequences.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParseValue}, \macro{\JSONParseArrayValues} and \macro{\JSONParseArrayValuesMap}.
\section{Main user commands}
\begin{macrodef}
|\JSONParse|[<options>]{<token variable>}{<JSON string>}
\end{macrodef}
The command \macro{\JSONParse} is used to parse a JSON string and store the parsed result in a token variable (a property list). The second argument takes the name of the token variable that is created by the command. The third argument takes the JSON string to be parsed.
For example, using \macro{\JSONParse{\myJSONdata}{ { "key" : "value" } }}, the relevant JSON string will be parsed and the result stored in the token variable \macro{\myJSONdata} as property list. In this case, the property list only consists of one entry with the key \macro{key} and the value \macro{value}. The command \macro{\JSONParseValue{\myJSONdata}{key}}, for example, can then be used to extract the relevant value from this property list (see the description below).
The first optional argument can be used to pass options to the command that are then applied locally.
\begin{macrodef}
|\JSONParseFromFile|[<options>]{<token variable>}{<JSON file>}
\end{macrodef}
The command \macro{\JSONParseFromFile} is used to parse a JSON file and store the parsed result in a token variable (a property list). It works the same way as \macro{\JSONParse}, but instead of a JSON string, it takes as third argument the path to the JSON file relative to the working directory.
\begin{macrodef}
|\JSONParseKeys|{<token variable>}{<token variable>}
\end{macrodef}
The command \macro{\JSONParseKeys} is used to store all top-level keys of a parsed JSON object as array into a token variable. The command takes as first argument the token variable that holds the parsed JSON data. The second argument takes the token variable that is assigned a JSON array containing the top-level keys of the object represented by the token variable in the first argument. The token variable to store the keys as array is created if it does not exist.
\begin{macrodef}
|\JSONParseValue|[<options>]{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseValue} is used to select values from the token variable (property list) that has been created using the commands \macro{\JSONParse} or \macro{\JSONParseFromFile}. The second argument takes the token variable that holds the parsed JSON data. The third argument takes the key to select the relevant entry from the parsed JSON data using JavaScript syntax.
If the JSON string \macro{{ "key" : "value" }} is parsed into the token variable \macro{\myJSONdata}, using \macro{\JSONParseValue{\myJSONdata}{key}} would extract the value associated with the key \macro{key}, which in this case is \macro{value}, and typeset it to the document.
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 first optional argument can be used to pass options to the command, such as \macro{escape} or \macro{rescan}, that are then applied locally. When the option \macro{rescan} is used, the token list is rescanned before it is typeset (which means that all category codes that may have been changed before are set to the default values). This is the default behaviour. If rescanning is not desired, pass the option \macro{rescan=false} to the 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.
The command \macro{\JSONParseValue} is not expandable and can therefore not be used as argument of certain other arguments where expansion is needed. In such cases, the expandable command \macro{\JSONParseExpandableValue} should be used.
\begin{macrodef}
|\JSONParseExpandableValue|{<token variable>}{<key>}
\end{macrodef}
Whole objects or arrays can be output as JSON string for further use in other macros using the expandable command \macro{\JSONParseExpandableValue}. The value that is returned by this command is typically a string variable where all characters have category code 12 (``other''), except for spaces and (horizontal) tabs that have category code 10 (``space''). This should be kept in mind if string comparisons should be made. A comparison against a token list with the default category codes used by TeX won't work, since letters will have category code 11 (``letter''), but it is possible to use \macro{\detokenize} to set the category codes of the token list in such a way that the comparison works.
For example, if the JSON string \macro{{ "key" : "value" }} has been parsed into the token variable \macro{\myJSONdata}, the command \macro{\JSONParseExpandableValue{\myJSONdata}{key}} will expand to the exact same token list as \macro{\detokenize{value}} with all characters having category code 12 (``other'').
\begin{macrodef}
|\JSONParseSetValue|{<token variable>}{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseValueSet} can be used to a select a value from the token variable that stores the parsed JSON data via a key and store this value globally in another token variable.
The first argument denotes the token variable where the value should be stored into. If this token variable has not yet been defined, it will be created by this command. The second argument represents the token variable (property list) that has been created using the commands \macro{\JSONParse} or \macro{\JSONParseFromFile} and that stores the parsed JSON data. The third argument takes the key to select the relevant value.
The token list returned by this command is a string variable where all characters have category code 12 (``other''), except for spaces and (horizontal) tabs that have category code 10 (``space'').
\begin{macrodef}
|\JSONParseSetRescanValue|{<token variable>}{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseSetRescanValue} works the same way and also takes the same arguments as \macro{\JSONParseSetValue} except that it rescans the return value before storing it globally in the token variable. This means that the value stored in the token list will have the category codes TeX uses per default.
This can, for example, be necessary when numbers stored in the JSON data in scientific format should be formatted using the \macro{siunitx} package. The rescan is needed here, because otherwise the character \macro{e} would have the wrong category code and would hence not be recognised by the formatting parser as exponent marker. Let us assume the key \macro{number} in some JSON source parsed into the token variable \macro{\myJSONnumber} represents the value \macro{-1.1e-1}, then the following could be used to format the output:
\JSONParse{\myJSONnumber}{ { "number" : -1.1e-1 } }
\begin{codeexamplecolumns}
\JSONParseSetRescanValue{\mynumber}
{\myJSONnumber}{number}
\num{\mynumber}
\end{codeexamplecolumns}
\begin{macrodef}
|\JSONParseArrayValues|[<options>]{<token variable>}{<key>}[<subkey>]{<string>}
\end{macrodef}
The command \macro{\JSONParseArrayValues} is used to select all values from an array from a parsed JSON string or JSON file. The second argument takes the token variable that holds the parsed JSON data. The first argument takes the key to select the relevant entry from the parsed JSON data using JavaScript syntax. The third argument is optional and can be used to pass a subkey, i.\,e. a key that is used to select a value for every item. The last argument takes a string that is inserted between all values when they are typeset.
For example, let us assume the following JSON data structure is parsed into the token variable \macro{\myJSONdata}:
\begin{codeexample}
{
"array" : [
{
"key_a" : "one" ,
"key_b" : "two"
} ,
{
"key_a" : "three" ,
"key_b" : "four"
}
]
}
\end{codeexample}
\JSONParse{\myJSONdata}{ { "array" : [ { "key_a" : "one" , "key_b" : "two" } , { "key_a" : "three" , "key_b" : "four" } ] } }
Then, when using \macro{\JSONParseArrayValues{\myJSONdata}{array}[key_a]{, }}, `\JSONParseArrayValues{\myJSONdata}{array}[key_a]{, }' is typeset to the document.
The first optional argument can be used to pass options to the command, such as \macro{escape} or \macro{rescan}, that are then applied locally.
\begin{macrodef}
|\JSONParseArrayValuesMap|[<options>]{<token variable>}{<key>}[<subkey>]
{<command name>}[<before code>][<after code>]
\end{macrodef}
The command \macro{\JSONParseArrayValuesMap} takes the same first three arguments as the command \macro{\JSONParseArrayValues} and works in a similar way. However, instead of a string that is added between the array items, it takes a command name as fourth argument. This command can be defined beforehand and will be called for every array item. Inside its definition, the commands \macro{\JSONParseArrayIndex}, \macro{\JSONParseArrayKey} and \macro{\JSONParseArrayValue} can be used which are updated for each item and output the index, the key and the value of the current item respectively. Note that these commands are defined globally to make accessing them as easy as possible.
For example, let us assume the same JSON data structure as defined above parsed into the token variable \macro{\myJSONdata}. Then, the following can be done:
\begin{codeexamplecolumns}
\newcommand{\myJSONitem}{
\item \emph{\JSONParseArrayValue}
}
\begin{itemize}
\JSONParseArrayValuesMap{\myJSONdata}
{array}[key_a]{myJSONitem}
\end{itemize}
\end{codeexamplecolumns}
It is possible to make use of multiple subkeys by passing them as a comma separated list as third argument to the command. Inside the command that is called for every array item, the different keys and values can be access via commands numbered with uppercase Roman numerals such as \macro{\JSONParseArrayKeyI}, \macro{\JSONParseArrayKeyII}, \macro{\JSONParseArrayKeyIII} etc.\ and \macro{\JSONParseArrayValueI}, \macro{\JSONParseArrayValueII}, \macro{\JSONParseArrayValueIII} etc.
We can extend the above example in the following way:
\begin{codeexamplecolumns}
\newcommand{\myJSONitem}{
\item \emph{\JSONParseArrayValueI :}
\JSONParseArrayValueII
}
\begin{itemize}
\JSONParseArrayValuesMap{\myJSONdata}
{array}[key_a,key_b]{myJSONitem}
\end{itemize}
\end{codeexamplecolumns}
The command additionally takes two optional arguments at sixth and seventh position. These arguments can be used to place code before and after the output that is generated by the command called for every array item, for example for typesetting tabular contents.
Typesetting the above example in a tabular way can be achieved as follows:
\begin{codeexamplecolumns}
\newcommand{\myJSONitem}{
\JSONParseArrayValueI &
\JSONParseArrayValueII \\
}
\JSONParseArrayValuesMap{\myJSONdata}
{array}[key_a,key_b]{myJSONitem}
[\begin{tabular}{ c c }
\textbf{key a} &
\textbf{key b} \\ \hline]
[\hline \end{tabular}]
\end{codeexamplecolumns}
Finally, the first optional argument of the command can be used to pass options to the command, such as \macro{escape} or \macro{rescan}, that are then applied locally.
\begin{macrodef}
|\JSONParseArrayCount|{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseArrayCount} takes as first argument a token variable holding a parsed JSON string or JSON file and as second argument a key. It returns an integer representing the number of items contained in the selected array.
\subsection{Externalising parsed JSON data}\label{sec:externalizing}
Parsing large JSON files can take quite a while. In order to speed up follow-up compilation runs, this package provides a way to store parsed JSON data for future use. Once a file for externalization has been created, the package will try to load the data from this file instead of parsing the JSON data again.
\begin{macrodef}
|externalize|
|externalize|={<boolean>}
\end{macrodef}
With the key \macro{externalize} set (or set to true), a file will be created in the working directory that stores the externalization of the parsed JSON data. The file name gets the extension \macro{.jsonparse}. The file name is created automatically and consists of the name of the current file followed by an underscore and the name of the token variable where the JSON data is stored into. If a file with the same name and file extension already exists, an error will be issued.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
|externalize prefix|={<string>}
\end{macrodef}
With the key \macro{externalize prefix}, a prefix can be defined that is added to the file name. Per default this is an empty string.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
|externalize file name|={<token list>}
\end{macrodef}
The key \macro{externalize file name} sets the schema for the file name. The default schema is as follows:
\begin{codeexample}
\l_jsonparse_externalize_prefix_str \c_sys_jobname_str
\c_underscore_str \l_jsonparse_current_prop_str
\end{codeexample}
The token variable \macro{\l_jsonparse_externalize_prefix_str} contains the prefix that is set using the key \macro{externalize prefix}. \macro{\c_sys_jobname_str} holds the name of the current file (the current job name), \macro{\c_underscore_str} is an underscore and the token variable \macro{\l_jsonparse_current_prop_str} contains the name of the property list where the relevant JSON data is stored into.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
|\JSONParsePut|{<token variable>}{<key>}[<JSON string>]
\end{macrodef}
The command \macro{\JSONParsePut} is used by the externalization procedure to re-read already parsed JSON data to the main file. It just adds a key-value pair to the property list (where the value part is read as string). Hence, it can also be used to append more entries to an already existing property list containing parsed JSON data.
\subsection{Changing separators, output and other options}\label{sec:options}
The package provides a set of keys can be set to change the separators used to select the relevant value in the JSON structure, the output that is generated from the JSON data as well as other things.
\begin{macrodef}
|\JSONParseSet|{<options>}
\end{macrodef}
The commands \macro{\JSONParseSet} can be used to specify options via key-value pairs (separated by commas). Keys that are presented here as a subkey (i.\,e. preceded by another key and a slash) can also be set using the syntax \macro{key={subkey}} and multiple subkeys belonging to one key can be combined using a comma as separator. Several user commands allow to pass keys directly which are then applied locally. The following keys are available:
\begin{macrodef}
separator/|child|={<string>}
separator/|array left|={<string>}
separator/|array right|={<string>}
\end{macrodef}
With the key \macro{separator/child}, the separator for child objects that is used in the syntax to select a specific value in the JSON data structure can be changed. Per default, the child separator is a dot (\macro{.}). Changing the separator can be useful if keys in the JSON structure already use these characters.
With the keys \macro{separator/array left} and \macro{separator/array right}, the separators for arrays that are used in the syntax to select a specific value in the JSON data structure can be changed. Per default, the separators are square brackets (\macro{[} and \macro{]}). Changing the separators can be useful if keys in the JSON structure already use these characters. Changing these separators to curly braces (\macro{{}}) is not supported due to their grouping function in TeX.
These keys can be set using \macro{\JSONParseSet}. They can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
|zero-based|
|zero-based|={<boolean>}
\end{macrodef}
If set (or explicitly set to \macro{true}), the key \macro{zero-based} sets the numbering of the index of array items to zero-based. If set to false, the indexing starts with one instead. Per default, the package uses zero-based indexing to resemble JavaScript notation.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
replace/|true|={<string>}
replace/|false|={<string>}
replace/|null|={<string>}
\end{macrodef}
With the keys \macro{replace/true}, \macro{replace/false} and \macro{replace/null}, the string that is typeset for true, false and null values can be changed. The default strings that are typeset are \macro{true}, \macro{false} and \macro{null} respectively. Only strings can be used as replacement. These replacements take place already during parsing.
These keys can be set using \macro{\JSONParseSet}. They can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\begin{macrodef}
replace/|backspace|={<string>}
replace/|formfeed|={<string>}
replace/|linefeed|={<string>}
replace/|carriage return|={<string>}
replace/|horizontal tab|={<string>}
\end{macrodef}
These keys can be used to set the replacement text for the JSON escape sequences \macro{\b} (backspace), \macro{\f} (formfeed), \macro{\n} (linefeed), \macro{\r} (carriage return) and \macro{\t} (horizontal tab). The default replacement string is a space. Only strings can be used as replacement. These replacements take place only during typesetting.
These keys can be set using \macro{\JSONParseSet}. They can also be set locally as option to the commands \macro{\JSONParseValue}, \macro{\JSONParseArrayValues} and \macro{\JSONParseArrayValuesMap}.
\begin{macrodef}
|check num|
|check num|={<boolean>}
\end{macrodef}
If set to \macro{false}, the key \macro{check num} omits an internal check of numerical expressions against the JSON specification for numbers. Turning off this feature can increase the parsing speed.
This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}.
\subsection{L3 commands}
\begin{macrodef}
|\jsonparse_parse:n| {<JSON string>}
\end{macrodef}
The command \macro{\jsonparse_parse:n} takes as argument a JSON string and populates the token variable (property list) \macro{\g_jsonparse_entries_prop} with key-value pairs representing all elements of the JSON data structure represented by this string. This command does not escape the input in any way.
\begin{macrodef}
|\jsonparse_parse_to_prop:Nn| <token variable> {<JSON string>}
\end{macrodef}
The command \macro{\jsonparse_parse_to_prop:Nn} creates the token variable given as the first arguments as property list and, after having called \macro{\jsonparse_parse:n} using the second argument, sets this newly created property list equal to \macro{\g_jsonparse_entries_prop}. If escaping is activated, this command will pre-process the input according to the selected escaping mode before forwarding it to \macro{\jsonparse_parse:n}. See more on escaping above in section \ref{sec:escaping}.
\begin{macrodef}
|\jsonparse_filter:Nn| <token variable> {<key>}
\end{macrodef}
The command \macro{\jsonparse_parse_to_prop:Nn} processes the token variable given as the first arguments as property list and filters it according to the key given as second argument. Filtering means that for every entry in the property list, the key of this entry is compared against the key given to the command. If the key in the property list starts with the given key, the matching part is removed from the key in the property list. If the keys do not match, the entry is completely removed from the property list.
\begin{macrodef}
|\jsonparse_array_count:NN| <token variable> <integer variable>
\end{macrodef}
The command \macro{\jsonparse_array_count:NN} processes the token variable given as the first arguments as property list and, assuming that it is an array, counts its items and stores the result in the integer variable. If the token variable does not expand to a key that represents an array item, that is if the key does not start with the character defined by \macro{separator/array left}, the command will return an error. The command \macro{\JSONParseArrayCount} serves as a wrapper of this command.
\begin{macrodef}
|\jsonparse_if_num:nTF| {<string>} {<true code>} {<false code>}
|\jsonparse_if_num:nT| {<string>} {<true code>}
|\jsonparse_if_num:nF| {<string>} {<false code>}
|\jsonparse_if_num_p:n| {<string>}
\end{macrodef}
The command \macro{\jsonparse_if_num:nTF} checks whether a string is a valid JSON number according the relevant specification. It executes the true code if the string is a valid JSON number and the false code if not. The variants \macro{\jsonparse_if_num:nT} and \macro{\jsonparse_if_num:nF} work accordingly. The command \macro{\jsonparse_if_num_p:n} returns a boolean true or false (i.\,e. \macro{\c_true_bool} or \macro{\c_false_bool}).
% =====
\printchanges
\end{document}
%% End of file `jsonparse-doc.tex`.