% File: jsonparse-doc.tex
% Copyright 2024-2026 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{1.7.3}
\def\jsonparsefiledate{10 June 2026}

\usepackage[T1]{fontenc}
\usepackage{Alegreya}
\usepackage{AlegreyaSans}
\usepackage{FiraMono}

\usepackage{geometry, longtable, booktabs, siunitx, tcolorbox, hyperref}
\geometry{margin=25mm, left=45mm}
\urlstyle{same}

\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[R]{\thepage}

\ExplSyntaxOn
\NewDocumentCommand{\fnstars}{m}{
  \int_step_inline:nn { \value{#1} } { * }
}
\ExplSyntaxOff

\linespread{1.1}\selectfont
\addtolength{\skip\footins}{1em plus 5pt}
\makeatletter
\renewcommand*{\thefootnote}{\fnstars{footnote}}
\renewcommand{\@makefnmark}{\normalfont\@thefnmark}
\renewcommand{\@makefntext}[1]{%
  \noindent\hbox to 1em{\normalfont\@thefnmark\hss}~#1%
}
\makeatother

\tcbuselibrary{skins,listings}
\lstdefinestyle{jsonparsedocmacro}{
  basicstyle=\small\ttfamily,
  literate=*{<}{{{\color{black!50}\guilsinglleft}}}1
    {>}{{{\color{black!50}\guilsinglright}}}1,
  keywords={},
  moredelim=[is][\bfseries]{|}{|},
  moredelim=[is][\bfseries\itshape]{?}{?},
  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}
    \setlength\itemsep{0pt}
    \int_step_inline:nn { \l_jsonparse_doc_change_int } {
      \item[
        \prop_item:cn { l_jsonparse_doc_change_
        \int_to_roman:n { ##1 } _prop } { version } ~
        \normalfont{ (
          \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

\NewDocumentCommand{\expandablestarcode}{ O{0,0} }{
  \fill[black!50, shift={([xshift={-10pt}, yshift={-10pt-0.5em}]#1)}]
    (90:3.75pt)
    \foreach \i in {1,...,4} {
      -- ({90+360/5*\i*2}:3.75pt)
    } -- cycle;
}

\NewDocumentCommand{\expandablestar}{}{
  \tikz{\expandablestarcode}
}

\NewDocumentCommand{\warning}{}{%
  \begin{tikzpicture}[overlay, baseline={(w.base)}]
    \node[circle, fill, black!25!red!10, text=black!25!red, outer sep=0pt]
      (w) at (-3em,0pt) {\bfseries !};
    \fill[black!25!red!10]
      (w.east) |- (w.south) -- cycle;
  \end{tikzpicture}%
}

\tcbset{
  size=small,
  arc=2.5pt,
  outer arc=2.5pt,
  colframe=black!10,
  colback=black!10,
  title style hook/.style={},
}

\NewTCBListing{macrodef}{ s o }{
  listing only,
  listing style={jsonparsedocmacro},
  grow to left by=2cm,
  boxrule=0pt,
  after={\par\smallskip\noindent},
  enhanced,
  IfValueT={#2}{
    hypertarget=#2
  },
  IfBooleanT={#1}{
    overlay={
      \expandablestarcode[frame.north east]
    }
  }
}

\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}
}

\NewTCBListing{macrodeprecated}{ s }{
  listing only,
  listing style={jsonparsedocmacro},
  boxrule=0pt,
  width={0.5\linewidth-2.5pt},
  box align=top,
  after=\hfill,
  colframe=black!25!red!10,
  colback=black!25!red!10,
  enhanced,
  IfBooleanT={#1}{
    overlay={
      \fill[black!25!red!10]
        ([yshift={5pt-1.5em}]frame.north east)
        -- ++(5pt,-5pt) -- ++(-5pt,-5pt)
        -- cycle;
    }
  }
}

\NewTCBListing{macroreplacement}{ }{
  listing only,
  listing style={jsonparsedocmacro},
  boxrule=0pt,
  width={0.5\linewidth-2.5pt},
  box align=top,
  before={},
  colframe=black!25!green!10,
  colback=black!25!green!10
}

\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
}{\MathCollectFalse\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:mail@jasperhabicht.de}{mail@jasperhabicht.de}. 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: \textcopyright{} 2024--2026 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; switching to linked property lists.}
%\changes{v0.9.11}{2025/01/15}{Bug fixes; adding additional command to loop through arrays.}
\changes{v0.9.12}{2025/01/17}{Bug fixes; adding commands to access items in arrays.}
%\changes{v1.0.0}{2025/01/20}{Streamlining of code, unification of command structure.}
\changes{v1.0.1}{2025/01/21}{Fixes in documentation. Added user command for filtering.}
\changes{v1.0.2}{2025/01/23}{Support for Unicode surrogate pairs.}
%\changes{v1.0.3}{2025/01/26}{Test for valid JSON numbers expandable.}
\changes{v1.1.0}{2025/01/30}{Unified names of user functions; renaming key for keywords.}
\changes{v1.1.1}{2025/02/03}{Added option to store result of mapped inline function.}
\changes{v1.1.2}{2025/02/08}{Added option to store result of array function.}
%\changes{v1.1.3}{2025/02/13}{Bug fixes.}
%\changes{v1.2.0}{2025/02/22}{Unified option to store result.}
\changes{v1.2.1}{2025/02/24}{Unified functions, added option to store result globally.}
%\changes{v1.2.2}{2025/02/25}{Fixes in documentation.}
\changes{v1.2.3}{2025/03/23}{Enabled nesting of mapped inline function.}
\changes{v1.3.0}{2025/03/25}{Enhancements in key setting mechanism.}
%\changes{v1.3.1}{2025/03/30}{Fixes in documentation. Bug fixes.}
%\changes{v1.3.2}{2025/04/07}{Bug fixes and code improvements.}
\changes{v1.4.0}{2025/04/10}{Enhancements in parsing speed.}
\changes{v1.5.0}{2025/04/20}{Enhancements in parsing speed. Bug fixes.}
%\changes{v1.5.1}{2025/05/05}{Bug fixes.}
%\changes{v1.5.2}{2025/05/06}{Bug fixes.}
\changes{v1.6.0}{2025/05/10}{Renaming of L3 functions. Bug fixes.}
%\changes{v1.6.1}{2025/06/03}{Bug fixes. FAQ in documentation.}
%\changes{v1.6.5}{2025/08/11}{Bug fixes.}
\changes{v1.6.6}{2025/08/27}{Various improvements. Added sockets for preparsing.}
%\changes{v1.6.7}{2025/10/07}{Enhanced backward compatibility.}
%\changes{v1.6.8}{2025/11/24}{Corrections and clarifications in documentation.}
\changes{v1.6.9}{2025/12/03}{Added option to locally assign plug to socket.}
%\changes{v1.6.10}{2025/12/10}{Added timestamp to externalized files.}
\changes{v1.6.11}{2026/01/18}{Added option to locally set zero-based indexing for mapping functions.}
%\changes{v1.6.12}{2026/01/20}{Fix in error handling.}
\changes{v1.7.0}{2026/01/22}{Improved expandability in mapping functions.}
%\changes{v1.7.1}{2026/01/28}{Minor improvement in array count function.}
%\changes{v1.7.2}{2026/04/15}{Corrections in documentation.}
%\changes{v1.7.3}{2026/06/10}{Improvement in object and array collection function.}

\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.\footnote{Credit for the idea of Jason, the JSON parsing horse, goes to Paulo Cereda and the circumstance of his presumably insufficiently illuminated workplace (or his late working hours).}

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.

The package is continuously being tested, but bugs cannot be ruled out. The author is grateful for reporting any bugs via GitHub at \url{https://github.com/jasperhabicht/jsonparse/issues}. A site for asking questions about the package and for suggestions for improvement is available at \url{https://github.com/jasperhabicht/jsonparse/discussions}.

\section{Frequently asked questions}

\subsection{Why does a comparison of two equal strings return false?}

Note that you probably need to use \macro{\JSONParseExpandableValue} if you want to compare a value from parsed JSON data with the contents of another token list. See the explanation \hyperlink{macro:expandablevalue}{below} for more details.

Also note that \macro{\JSONParseExpandableValue} returns a string with specific category codes, namely category code 12 (``other'') for all characters except spaces. Therefore, you need to test against another string. You can use \macro{\detokenize} for conversion. See section \ref{sec:general} for more information.

\subsection{Why does parsing take so long?}

Make sure that you use the most recent version of the package. Parsing speed is constantly being monitored and updates typically increase parsing speed.

If you don't need to access whole objects or arrays from the JSON data, you can set the key \macro{skip structures} which should increase parsing speed. See the explanation \hyperlink{key:skipstructures}{below} for more details.

If the JSON data contains a considerable amount of numbers, parsing speed can be increased slightly by setting \macro{validate numbers=false}. See the explanation \hyperlink{key:validatenumbers}{below} for more details.

If the JSON data does not change often, you can externalize the parsed result by setting the key \macro{externalize}. See section \ref{sec:externalizing} for more information.

\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 can be used with PDFLaTeX, LuaLaTeX or XeLaTeX. It should also work with upTeX. The package does not load any dependencies, but it needs a LaTeX kernel of 1 June 2022 or newer. It is recommended to use the package with an up-to-date TeX distribution.

\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. It will also show the relevant keys associated to the values. If the key \macro{skip structures} is not set (or not set to \macro{true}), objects and arrays will be shown as values to the respective keys, including the pseudo key \macro{.} (or the string defined using the key \macro{separator/child}) that represents the complete JSON string.

Let us assume that the following JSON data is parsed:

\begin{codeexample}
{
  "string" : "a" ,
  "boolean true" : true ,
  "boolean false" : false ,
  "null" : null ,
  "number" : -1.1e-1 ,
  "array" : [ "a" , "b" , "c" ]
}
\end{codeexample}

This will then result in the following output to the log:

\begin{codeexample}
Parsing JSON ...
(obj begin)
(key) string:
  (str) a
(key) boolean true:
  (tru) true
(key) boolean false:
  (fal) false
(key) null:
  (nul) null
(key) number:
  (num) -1.1e-1
(arr begin)
(key) array[0]:
  (str) a
(key) array[1]:
  (str) b
(key) array[2]:
  (str) c
(key) array:
  (arr) [ "a" , "b" , "c" ]
(arr end)
(key) .:
  (obj) { "string" : "a" , "boolean true" : true , "boolean false" :
  false , "null" : null , "number" : -1.1e-1 , "array" : [ "a" ,
  "b" , "c" ] }
(obj end)
JSON parsing done.
\end{codeexample}

The \macro{debug} 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}\label{sec:general}

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'').

During parsing, the package identifies JSON objects, arrays, strings, numbers, boolean values and null values from the JSON data. It stores all these values together with the relevant keys in a property list. Once the parsing process is done, every value can be retrieved from the property list by calling the relevant key. The package ignores whitespace in the JSON data. In general, the package accepts any valid JSON data. If a key is defined multiple times, the latter definition will silently overwrite the former.

\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 (re)defines 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 defined as \macro{\exp_not:N \"} and only expanded to \macro{"} when typeset, 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{\codepoint_generate:nn} that creates the character represented by the relevant four hex digits with category code 12 (``other''). If two escape sequences \macro{\u} with four hex digits each follow each other and together represent a Unicode surrogate pair, this surrogate pair is converted into the relevant Unicode codepoint.

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{replace} 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 expanded just before typesetting. Backslashes of TeX macros need to be escaped by another backslash. The TeX macros \macro{\"} and \macro{\\} must be escaped again in the JSON source so that they become \macro{\\\"} and \macro{\\\\} respectively.

\begin{macrodef}
|\$|{<token variable name>}{<key>}
\end{macrodef}
Using the control sequence \macro{\$}, it is possible to nest JSON strings into each other. Used inside the \macro{\JSONParse} command, 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" : \${myJSONdataA}{a} }
}

\JSONParseValue{\myJSONdataB}{d.b}
\end{codeexamplecolumns}

\warning Note that the control sequence \macro{\$} is replaced by the value exactly. Therefore, if the value happens to be a string, the control sequence \macro{\$} should be placed between quotation marks (\macro{"}) in order for the resulting string to be valid JSON. The control sequence \macro{\$} 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 or 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{\JSONParseArrayUse} and \macro{\JSONParseArrayMapFunction}.

\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{\JSONParseArrayUse} and \macro{\JSONParseArrayMapFunction}.

\section{Main user commands}

The first part of this section describes the basic commands for parsing JSON data and retrieving values from parsed JSON data. The second part of this section describes the various commands for handling arrays provided by this package. Commands marked with a star (\expandablestar) are fully expandable.

\subsection{Basic parsing commands}

\begin{macrodef}
|\JSONParse|[<options>]{<token variable>}{<JSON string>}
\end{macrodef}
The command \macro{\JSONParse} is used to parse a JSON string and globally store the parsed result in a token variable (a property list). The first mandatory argument takes the name of the token variable that is created by the command. The second mandatory 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 two entries of which one has the key \macro{key} and the value \macro{value} and the other represents the whole object. Once the JSON string has been parsed, the command \macro{\JSONParseValue{\myJSONdata}{key}}, for example, can be used to extract the relevant value from this property list (see the description below).

The optional argument of the command \macro{\JSONParse} can be used to pass options to the command that are then applied locally.

\warning The command \macro{\JSONParse} takes the JSON string as verbatim argument which means that the command can't be used inside a macro argument. One consequence of this for example is that when using the \macro{beamer} document class, the command \macro{\JSONParse} can only be used inside the \macro{frame} environment if the \macro{fragile} option is set.

\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}
|\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 first mandatory argument takes the token variable that holds the parsed JSON data. The second mandatory 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 optional argument can be used to pass options such as \macro{escape} or \macro{rescan} to the command 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 behavior. If rescanning is not desired, pass the option \macro{rescan=false} to the command.

When a key is associated with an object or array (and the key \macro{skip structures} is not set), the whole object or array is output as JSON string. Additionally, the special key \macro{.} (or the string defined using the key \macro{separator/child}) returns the whole JSON object (or the whole JSON array if the JSON data only consists of one array) as string where all characters (except for spaces and tabs) have category code 12 (``other'').

\warning 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}[key:storein]
|store in|={<token variable>}
\end{macrodef}
The command \macro{\JSONParseValue} accepts the key \macro{store in} that can be used to store the return value in another token variable. If the token variable given as option to the \macro{store in} key has not yet been defined, it will be created by this command.

Per default, 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'').

The key \macro{store in} can be used together with the key \macro{rescan} to rescan the return value before storing it in the token variable. This means that the value stored in the token list will have the category codes TeX uses per default. Option settings such as the \macro{escape} option are taken into consideration during the rescan process.

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 recognized 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}
\JSONParseValue
  [rescan, store in=\mynumber]
  {\myJSONnumber}{number}
\num{\mynumber}
\end{codeexamplecolumns}

The key \macro{store in} can also be set using \macro{\JSONParseSet}. Calling \macro{store in={}} will reset it to its default (empty) value.

\begin{macrodef}*[macro:expandablevalue]
|\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 have the same meaning as \macro{\detokenize{value}} and expand to a token list with all characters having category code 12 (``other'').

\begin{macrodef}
|\JSONParseKeys|[<options>]{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseKeys} is used to get all top-level keys of a JSON object as JSON array and return this array as string where all characters (except for spaces and tabs) have category code 12 (``other''). The first mandatory argument of the command takes the token variable that holds the parsed JSON data. The second mandatory argument takes the key to select the relevant entry from the parsed JSON data using JavaScript syntax.

The command \macro{\JSONParseKeys} accepts as option the key \macro{store in} to get all top-level keys of a JSON object as JSON array and parse this array into a token variable. Note that the return value is a property list in this case, not a string. The token variable to store the keys as array is created if it does not exist.

As an example, let us assume that 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" } ] } }

We can then generate an array consisting of all keys of the object that is the first item of the array using \macro{\JSONParseKeys{\myJSONdata}{array[0]}}. We can also generate an array consisting of all top-level keys of the parsed JSON data using \macro{\JSONParseKeys{\myJSONdata}{.}} where \macro{.} is the pseudo key representing the complete parsed JSON string. Note that in addition to the key of an array, keys for each item of this array will be added to the array of keys:

\begin{codeexamplecolumns}
\JSONParseKeys{\myJSONdata}{array[0]}

\JSONParseKeys{\myJSONdata}{.}
\end{codeexamplecolumns}

If we store such an array of keys in the token variable \macro{\myJSONkeys}, we can for example access the first item of this array of keys using \macro{\JSONParseValue{\myJSONkeys}{[0]}}:

\begin{codeexamplecolumns}
\JSONParseKeys[store in=\myJSONkeys]
  {\myJSONdata}{.}
\JSONParseValue{\myJSONkeys}{[0]}
\end{codeexamplecolumns}

Note that the underscores in the names of the keys can be printed without changing to math mode in the above example because they are stored as strings where all characters (except for spaces and tabs) have category code 12 (``other'').

\begin{macrodef}
|\JSONParseFilter|{<token variable>}{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseFilter} is used to select a part (such as an object or an array) of a JSON object or JSON array and parse this into a token variable (a property list). The first argument denotes the token variable where the value should be stored into. The second argument of the command 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.

\subsection{Commands for handling arrays}

The package offers a variety of commands that can be used to process JSON arrays. Three commands are provided to loop through arrays, \macro{\JSONParseArrayUse}, \macro{\JSONParseArrayMapFunction} and \macro{\JSONParseArrayMapInline} which offer different functionality for different use cases. All three commands are implemented in a unique way and it should not be expected that what works with one of these commands also works with another. The commands differ in various respects, for example:

\begin{itemize}
  \item With \macro{\JSONParseArrayUse} and \macro{\JSONParseArrayMapInline}, it is possible to store the result in a token list for later use via the option key \macro{store in}, but such is not possible with \macro{\JSONParseArrayMapFunction}.
  \item It is possible to store non-expandable commands (such as \macro{\emph} or \macro{\textbf}) in a token list using \macro{\JSONParseArrayUse}, but not using \macro{\JSONParseArrayMapInline}.
\end{itemize}

\begin{macrodef}
|\JSONParseArrayCount|[<options>]{<token variable>}{<key>}
\end{macrodef}
The command \macro{\JSONParseArrayCount} takes as first mandatory argument a token variable holding a parsed JSON string or JSON file and as second mandatory argument a key to select an array in the JSON data. It returns an integer representing the number of items contained in the selected array.

The command \macro{\JSONParseArrayCount} accepts the use of the key \macro{store in} to store the number of items contained in the selected array in a token variable.

\begin{macrodef}[macro:arrayuse]
|\JSONParseArrayUse|[<options>]{<token variable>}{<key>}[<subkey>]{<string>}
\end{macrodef}
The command \macro{\JSONParseArrayUse} is used to select all values from an array from a parsed JSON string or JSON file. The first mandatory argument takes the token variable that holds the parsed JSON data. The second mandatory argument takes the key to select the relevant entry from the parsed JSON data using JavaScript syntax. The second optional argument 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.

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.

Let us again assume the following JSON data structure being parsed into the token variable \macro{\myJSONdata}:

\begin{codeexample}
{
  "array" : [
    {
      "key_a" : "one" ,
      "key_b" : "two"
    } ,
    {
      "key_a" : "three" ,
      "key_b" : "four"
    }
  ]
}
\end{codeexample}

When using \macro{\JSONParseArrayUse{\myJSONdata}{array}[key_a]{, }}, `\JSONParseArrayUse{\myJSONdata}{array}[key_a]{, }' is then typeset to the document.

The command \macro{\JSONParseArrayUse} accepts as option set in the first optional argument the key \macro{store in} which takes a token variable into which the result of the command should be stored. Storing the result of the mapped inline function can be helpful if JSON data should be reformatted for use in another function.

\begin{codeexamplecolumns}
\JSONParseArrayUse[store in=\myJSONitems]
  {\myJSONdata}{array}[key_a]{,}

\begin{tikzpicture}
  \foreach \x [count=\i] in \myJSONitems {
    \fill[blue] (\i,0) circle[radius=2pt]
      node[above=5pt, black] {\x};
  }
\end{tikzpicture}
\end{codeexamplecolumns}

The command \macro{\JSONParseArrayUse} also accepts as option set in the first optional argument the key \macro{zero-based} to set the initial value of the mapping counter to the intended value if the key \macro{zero-based} is not set globally.

\begin{macrodef}[macro:arraymapfunction]
|\JSONParseArrayMapFunction|[<options>]{<token variable>}{<key>}[<subkey>]
  {<command>}
\end{macrodef}
The command \macro{\JSONParseArrayMapFunction} works in a similar way and takes the same first four arguments as the command \macro{\JSONParseArrayUse}. However, instead of a string that is added between the array items, it takes a command (a token list) as last 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}
  \JSONParseArrayMapFunction{\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 fourth argument to the command. Inside the command that is called for every array item, the different keys and values can be accessed 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}
  \JSONParseArrayMapFunction{\myJSONdata}
    {array}[key_a,key_b]{\myJSONitem}
\end{itemize}
\end{codeexamplecolumns}

\begin{macrodef}
|code before|={<code>}
|code after|={<code>}
\end{macrodef}

The command \macro{\JSONParseArrayMapFunction} accepts \macro{code before} and \macro{code after} as options. These options 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 \\
}

\JSONParseArrayMapFunction[
  code before={
    \begin{tabular}{ c c }
      \textbf{key a} &
      \textbf{key b} \\ \hline
  },
  code after={
      \hline
    \end{tabular}
  }
]{\myJSONdata}{array}[key_a,key_b]
  {\myJSONitem}
\end{codeexamplecolumns}

The command \macro{\JSONParseArrayMapFunction} accepts as option set in the first optional argument the key \macro{zero-based} to set the initial value of the mapping counter to the intended value if the key \macro{zero-based} is not set globally.

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}
|\JSONParseArrayMapInline|[<options>]{<token variable>}{<key>}{<inline function>}
\end{macrodef}
The command \macro{\JSONParseArrayMapInline} takes as first mandatory argument a token variable holding a parsed JSON string or JSON file and as second mandatory argument a key to select an array in the JSON data. The last argument can contain any code where the index of the current item is represented by \macro{#1}. The code may contain another instance of \macro{\JSONParseArrayMapInline}, which means that the command can be nested.

Using again the above example, the mechanism could be implemented as follows:

\begin{codeexamplecolumns}
\begin{itemize}
  \JSONParseArrayMapInline{\myJSONdata}
    {array}{
      \item \JSONParseValue{\myJSONdata}
        {array[#1].key_a}
    }
\end{itemize}
\end{codeexamplecolumns}

Making use of the commands \macro{\JSONParseKeys} and \macro{\JSONParseValue} together with the \macro{store in} option, keys and values can be accessed:

\begin{codeexamplecolumns}
\JSONParseArrayMapInline{\myJSONdata}
  {array}{
    \JSONParseKeys[store in=\mykeys]
      {\myJSONdata}{array[#1]}
    \JSONParseValue
      [store in=\mykeya, rescan=false]
      {\mykeys}{[0]}
    \JSONParseValue
      [store in=\mykeyb, rescan=false]
      {\mykeys}{[1]}

    \emph{\mykeya :}
    \JSONParseValue{\myJSONdata}
      {array[#1].\mykeya}\par

    \emph{\mykeyb :}
    \JSONParseValue{\myJSONdata}
      {array[#1].\mykeyb}\par\bigskip
  }
\end{codeexamplecolumns}

Note that the underscores in the names of the keys can be printed without changing to math mode in the above example by switching off rescanning via \macro{rescan=false}. This is possible because all JSON data is stored as string where all characters (except for spaces and tabs) have category code 12 (``other'').

The command \macro{\JSONParseArrayMapInline} accepts as option set in the optional argument the key \macro{store in} which takes a token variable into which the result of the mapped inline function should be stored. Refer to the relevant explanations to command \macro{\JSONParseArrayUse} \hyperlink{macro:arrayuse}{above} for more information.

The command \macro{\JSONParseArrayMapInline} accepts as option set in the optional argument the key \macro{zero-based} to set the initial value of the mapping counter to the intended value if the key \macro{zero-based} is not set globally.

\warning In order for the result to be stored in a token variable, the inline function needs to be fully expandable. For example, it is not possible to use the command \macro{\JSONParseValue} in the code of the inline function while using the command \macro{\JSONParseExpandableValue} is allowed. Note that the command \macro{\JSONParseArrayMapInline} itself is not expandable which means that nested use of this command prevents storing the result in a token variable.

Storing the result of the mapped inline function can be helpful if JSON data should be reformatted for use in a plotting functions. An example for a use case with PGFPlots is shown below. In this example, the parsed JSON string \macro{{ "data": [ [0,0], [1,-1], [2,1] ] }} was stored in the token variable \macro{\myJSONplotdata}.

\JSONParse{\myJSONplotdata}{ { "data": [ [0,0], [1,-1], [2,1] ] } }
\pgfplotsset{width=5.25cm}

\begin{codeexamplecolumns}
\JSONParseArrayMapInline
  [store in={\myJSONplotcoords}]
  {\myJSONplotdata}{data}{
    (
    \JSONParseExpandableValue
      {\myJSONplotdata}{data[#1][0]}
    ,
    \JSONParseExpandableValue
      {\myJSONplotdata}{data[#1][1]}
    )
  }

\begin{tikzpicture}
  \begin{axis}
    \addplot coordinates
      {\myJSONplotcoords};
  \end{axis}
\end{tikzpicture}
\end{codeexamplecolumns}

\section{Externalizing parsed JSON data}\label{sec:externalizing}

Parsing large and complex 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 (without the leading backslash).

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.

\section{Changing parsing and typesetting behavior via option keys}\label{sec:options}

The package provides a set of keys that 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 command \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 such as \macro{key/subkey}) can also be set using the syntax \macro{key={subkey}} and multiple subkeys belonging to one key can be combined using commas as separator. Several user commands allow to pass keys directly which are then applied locally.

Not every key takes effect in every situation. Some keys affect the parsing procedure and thus need to be set before parsing. Some keys affect the typeset result and some keys only affect the typeset result when used in combination with specific commands.

\subsection{Keys affecting the parsing procedure}

Information about the key \macro{externalize} as well as about the related keys \macro{externalize prefix} and \macro{externalize file name} can be found above in section \ref{sec:externalizing}.

\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 key to select a specific value in the JSON data structure can be changed. Per default, the child separator is a dot (\macro{.}).

With the keys \macro{separator/array left} and \macro{separator/array right}, the separators for arrays that are used in the key to select a specific value in the JSON data structure can be changed. Per default, the separators are square brackets (\macro{[} and \macro{]}). Changing these separators to curly braces (\macro{{}}) is not supported due to their grouping function in TeX.

Changing the separators can be useful if keys in the JSON structure already use these characters. These settings 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}. When set using \macro{\JSONParseSet}, these keys only take effect when set before parsing.

\begin{macrodef}
|zero-based|
|zero-based|={<boolean>}
\end{macrodef}
If the key \macro{zero-based} is set (or explicitly set to \macro{true}), the index of array items starts with zero. If set to false, the indexing starts with one instead. Per default, the package uses zero-based indexing to match JavaScript notation. This setting affects indexing already during parsing.

This key can be set using \macro{\JSONParseSet}. It can also be set locally as option to the commands \macro{\JSONParse} and \macro{\JSONParseFromFile}. When set using \macro{\JSONParseSet}, this key only takes effect when set before parsing.

If this key is set locally as option to the command \macro{\JSONParse} or \macro{\JSONParseFromFile}, it is necessary to also set it locally as option to the array-handling commands \macro{\JSONParseArrayUse}, \macro{\JSONParseArrayMapFunction} and \macro{\JSONParseArrayMapInline} to let the relevant mapping function start from the correct value of the internal counter.

\begin{macrodef}[key:validatenumbers]
|validate numbers|
|validate numbers|={<boolean>}
\end{macrodef}
If set to \macro{false}, the key \macro{validate numbers} omits an internal validation of numerical expressions against the JSON specification for numbers. Turning off this feature can increase the parsing speed if many numbers are to be parsed. Validations are carried out per default.

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}[key:skipstructures]
|skip structures|
|skip structures|={<boolean>}
\end{macrodef}
If set or explicitly set to \macro{true}, the key \macro{skip structures} deactivates the storage of arrays and objects as values to the relative keys. Also, it omits storing of the whole JSON string as value with the pseudo key \macro{.} (or the string defined using the key \macro{separator/child}). Skipping structures is deactivated per default. Setting this key to true can speed up the parsing process and circumvent memory limitations.

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{Keys affecting the typesetting}

Some keys that change the typesetting behavior are explained in other parts of this documentation.

\begin{itemize}
\item Information about the keys \macro{escape} and \macro{rescan} can be found above in section \ref{sec:escaping}.
\item Information about the key \macro{store in} can be found \hyperlink{key:storein}{above} in the context of the description to the command \macro{\JSONParseValue} as well as in the description to \macro{\JSONParseKeys}, \macro{\JSONParseArrayCount}, \macro{\JSONParseArrayUse} and \macro{\JSONParseArrayMapInline}.
\item Information about the keys \macro{code before} and \macro{code after} can be found above in the description to the command \macro{\JSONParseArrayMapFunction} \hyperlink{macro:arraymapfunction}{above}.
\end{itemize}

\begin{macrodef}
keyword/|true|={<string>}
keyword/|false|={<string>}
keyword/|null|={<string>}
\end{macrodef}
With the keys \macro{keyword/true}, \macro{keyword/false} and \macro{keyword/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 should 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}. When set using \macro{\JSONParseSet}, these keys only take effect when set before parsing.

\begin{macrodef}
replace/|backspace|={<token list>}
replace/|formfeed|={<token list>}
replace/|linefeed|={<token list>}
replace/|carriage return|={<token list>}
replace/|horizontal tab|={<token list>}
\end{macrodef}
These keys can be used to set the replacement 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 is a space in each case. These replacements take place only during typesetting. They only take effect if \macro{rescan} is active.

\warning Note that commands such as \macro{\par} need to be masked (for example by using a copy created via \macro{\let}) in order to be used as replacement.

These keys can be set using \macro{\JSONParseSet}. They can also be set locally as option to the commands \macro{\JSONParseValue}, \macro{\JSONParseArrayUse} and \macro{\JSONParseArrayMapFunction}.

\begin{macrodef}
|global|
|global|={<boolean>}
\end{macrodef}
The key \macro{global} can be used together with the key \macro{store in} to globally set the value of the relevant token list. Detailed information about the key \macro{store in} can be found \hyperlink{key:storein}{above}.

\section{Preparsing via sockets}

The package provides two sockets \macro{jsonparse/preparse} and \macro{jsonparse/preparse-file} using which the code for the procedure for rescanning the JSON input can be changed. The code provided by the sockets should populate the token list \macro{\g_jsonparse_json_tl} with data that is eventually parsed into the property list for further use.

Two default plugs are provided and assigned per default for the two sockets. Both sockets require exactly one argument which can be referred to by \macro{#1} in the definition of the plugs. For the socket \macro{jsonparse/preparse} which is used in the command \macro{\JSONParse}, this represents the provided JSON input. For the socket \macro{jsonparse/preparse-file} which is used in the command \macro{\JSONParseFromFile}, this represents the file name. The two default plugs are defined as follows:

\begin{codeexample}
\socket_new_plug:nnn { jsonparse / preparse } { default } {
  \tl_set:Nn \obeyedline { ~ }
  \tl_gset_rescan:Nne \g_jsonparse_json_tl {
    \cctab_select:N \c_jsonparse_json_cctab
  } {#1}
}
\end{codeexample}

\begin{codeexample}
\socket_new_plug:nnn { jsonparse / preparse-file } { default } {
  \file_get:nnN {#1} { \cctab_select:N \c_jsonparse_json_cctab }
    \g_jsonparse_json_tl
}
\end{codeexample}

It is, for example, possible to make use of this mechanism by defining a new plug to parse JSONL data which consists of a number of JSON objects separated by a line break (the two lines with regular expression replacements ensure that no unwanted leading or trailing commas appear in the array):

\begin{codeexample}
\socket_new_plug:nnn { jsonparse / preparse } { jsonl } {
  \tl_set:Nn \obeyedline { , }
  \tl_gset_rescan:Nne \g_jsonparse_json_tl {
    \cctab_select:N \c_jsonparse_json_escape_cctab
  } { [ #1 ] }
  \regex_replace_once:nnN { \A\[, } { [ }
    \g_jsonparse_json_tl
  \regex_replace_once:nnN { ,\]\Z } { ] }
    \g_jsonparse_json_tl
}
\end{codeexample}

\begin{macrodef}
|preparse|={<string>}
\end{macrodef}
The commands \macro{\JSONParse} and \macro{\JSONParseFromFile} accept the key \macro{preparse} as option. The key takes as argument the name of the plug that will be assigned to the \macro{jsonparse/preparse} or \macro{jsonparse/preparse-file} socket and then used when parsing the relevant JSON string or file.

To assign the plug for all following calls of \macro{\JSONParse} or \macro{\JSONParseFromFile}, assign the plug use the command \macro{\AssignSocketPlug}. The above defined plug for JSONL for example can be assigned using \macro{\AssignSocketPlug{jsonparse/preparse}{jsonl}}.

\warning Changing the rescanning procedure via the provided sockets requires in-depth knowledge about how the parsing procedure works. It also requires knowledge about how TeX deals with category codes and control sequences.

\section{L3 token variables and commands}

The following token variables and commands are provided for defining user functions by package authors. For the conditional functions described below, apart from the variant that provides a true and a false branch, the two variants that only provide an argument for the true or for the false branch respectively are defined as well which is indicated by the letters {\itshape\macro{TF}} printed in italics. Commands marked with a star (\expandablestar) are fully expandable.

\begin{macrodef}
|\c_jsonparse_json_cctab|
\end{macrodef}
The token variable \macro{\c_jsonparse_json_cctab} holds the category code table that is used for rescanning JSON input. The definition is as follows:

\begin{codeexample}
\cctab_const:Nn \c_jsonparse_json_cctab {
  \cctab_select:N \c_str_cctab
  \char_set_catcode_space:n { 9 }
  \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
  }
}
\end{codeexample}

\begin{macrodef}
|\g_jsonparse_json_tl|
\end{macrodef}
The token variable \macro{\g_jsonparse_json_tl} holds the rescanned JSON input before it is parsed by the command \macro{\jsonparse_parse:n}.

\begin{macrodef}
|\g_jsonparse_entries_prop|
\end{macrodef}
The token variable \macro{\g_jsonparse_entries_prop} holds as property list all elements of a JSON data structure that was parsed by the command \macro{\jsonparse_parse:n}.

\begin{macrodef}
|\l_jsonparse_current_prop_str|
\end{macrodef}
The token variable \macro{\l_jsonparse_current_prop_str} holds the name of the property list as defined by the user when calling the command \macro{\JSONParse} or \macro{\JSONParseFromFile} (without the leading backslash).

\begin{macrodef}
|\l_jsonparse_externalize_prefix_str|
\end{macrodef}
The token variable \macro{\l_jsonparse_externalize_prefix_str} holds the prefix for externalization file names as defined by the user via the key \macro{externalize prefix}.

\begin{macrodef}
|\jsonparse_parse:n| {<JSON string>}
|\jsonparse_parse:o| {<JSON string>}
|\jsonparse_parse:e| {<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_set_parse:Nn| <token variable> {<JSON string>}
|\jsonparse_set_parse:No| <token variable> {<JSON string>}
|\jsonparse_set_parse:Ne| <token variable> {<JSON string>}
\end{macrodef}
The command \macro{\jsonparse_set_parse: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, locally 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_gset_parse:Nn| <token variable> {<JSON string>}
|\jsonparse_gset_parse:No| <token variable> {<JSON string>}
|\jsonparse_gset_parse:Ne| <token variable> {<JSON string>}
\end{macrodef}
The command \macro{\jsonparse_gset_parse:Nn} is identical to \macro{\jsonparse_set_parse:Nn} but with the property list being set globally.

\begin{macrodef}
|\jsonparse_set_parse_keys:NN| <string variable> <token variable>
\end{macrodef}
The command \macro{\jsonparse_set_parse_keys:NN} processes the token variable given as the second argument as property list and selects all top-level keys which are then stored in the string variable given as first argument as JSON array. The pseudo key \macro{.} (or the string defined using the key \macro{separator/child}) to select the complete JSON data is ignored. If the JSON data is an array, the indices of the items (wrapped into the separators defined by \macro{separator/array left} and \macro{separator/array right}) are used as keys.

\begin{macrodef}
|\jsonparse_rescan:n| {<JSON value>}
|\jsonparse_rescan:e| {<JSON value>}
\end{macrodef}
The command \macro{\jsonparse_rescan:n} rescans the JSON value given in the argument. Rescanning converts all tokens to their default category codes and TeX control sequences are expanded. 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.

\begin{macrodef}
|\jsonparse_set_rescan:Nn| <token variable> {<JSON value>}
|\jsonparse_set_rescan:Ne| <token variable> {<JSON value>}
|\jsonparse_set_rescan:cn| {<token variable name>} {<JSON value>}
|\jsonparse_set_rescan:ce| {<token variable name>} {<JSON value>}
\end{macrodef}
The command \macro{\jsonparse_set_rescan:Nn} rescans the JSON value given in the second argument and stores the result locally in the token variable specified in the first argument.

\begin{macrodef}
|\jsonparse_gset_rescan:Nn| <token variable> {<JSON value>}
|\jsonparse_gset_rescan:Ne| <token variable> {<JSON value>}
|\jsonparse_gset_rescan:cn| {<token variable name>} {<JSON value>}
|\jsonparse_gset_rescan:ce| {<token variable name>} {<JSON value>}
\end{macrodef}
The command \macro{\jsonparse_gset_rescan:Nn} rescans the JSON value given in the second argument and stores the result globally in the token variable specified in the first argument.

\begin{macrodef}
|\jsonparse_put_right_rescan:Nn| <token variable> {<JSON value>}
|\jsonparse_put_right_rescan:Ne| <token variable> {<JSON value>}
\end{macrodef}
The command \macro{\jsonparse_put_right_rescan:Nn} rescans the JSON value given in the second argument and adds the result locally to the end of the token variable specified in the first argument.

\begin{macrodef}
|\jsonparse_gput_right_rescan:Nn| <token variable> {<JSON value>}
|\jsonparse_gput_right_rescan:Ne| <token variable> {<JSON value>}
\end{macrodef}
The command \macro{\jsonparse_gput_right_rescan:Nn} rescans the JSON value given in the second argument and adds the result globally to the end of the token variable specified in the first argument.

\begin{macrodef}
|\jsonparse_set_filter:Nn| <token variable> {<key>}
\end{macrodef}
The command \macro{\jsonparse_set_filter:Nn} processes the token variable given as the first argument 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. If the second argument matches the pseudo key \macro{.} (or the string defined using the key \macro{separator/child}) exactly, the complete property list except for this key is returned.

\begin{macrodef}
|\jsonparse_set_array_count:NN| <integer variable> <token variable>
\end{macrodef}
The command \macro{\jsonparse_set_array_count:NN} processes the token variable given as the second argument as property list and, assuming that it is an array, counts its items and stores the result in the integer variable given as first argument. 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:n|?TF? {<string>} {<true code>} {<false code>}
|\jsonparse_if_num:V|?TF? <string variable> {<true code>} {<false code>}
|\jsonparse_if_num_p:n| {<string>}
|\jsonparse_if_num_p:V| <string variable>
\end{macrodef}
The expandable conditional function \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 that only provide an argument for the true or false case 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}).

\begin{macrodef}*
|\jsonparse_unicode_if_high_surrogate:n|?TF? {<codepoint>}
  {<true code>} {<false code>}
|\jsonparse_unicode_if_high_surrogate:e|?TF? {<codepoint>}
  {<true code>} {<false code>}
|\jsonparse_unicode_if_high_surrogate_p:n| {<codepoint>}
|\jsonparse_unicode_if_high_surrogate_p:e| {<codepoint>}
\end{macrodef}
The expandable conditional function \macro{\jsonparse_unicode_if_high_surrogate:nTF} checks whether the codepoint entered as argument (an integer that can be hexadecimal if preceded by \macro{"}) is in the range of \macro{"D800} and \macro{"DBFF} which means that it is the first part of a surrogate pair (a high surrogate). The conditional function executes the true or false code depending on the evaluation. The variants that only provide an argument for the true or false case work accordingly. The command \macro{\jsonparse_unicode_if_high_surrogate_p:n} returns a boolean true or false (i.\,e.\ \macro{\c_true_bool} or \macro{\c_false_bool}).

\begin{macrodef}*
|\jsonparse_unicode_if_low_surrogate:n|?TF? {<codepoint>}
  {<true code>} {<false code>}
|\jsonparse_unicode_if_low_surrogate:e|?TF? {<codepoint>}
  {<true code>} {<false code>}
|\jsonparse_unicode_if_low_surrogate_p:n| {<codepoint>}
|\jsonparse_unicode_if_low_surrogate_p:e| {<codepoint>}
\end{macrodef}
The expandable conditional function \macro{\jsonparse_unicode_if_low_surrogate:nTF} checks whether the codepoint entered as argument (an integer that can be hexadecimal if preceded by \macro{"}) is in the range of \macro{"DC00} and \macro{"DFFF} which means that it is the last part of a surrogate pair (a low surrogate). The conditional function executes the true or false code depending on the evaluation. The variants that only provide an argument for the true or false case work accordingly. The command \macro{\jsonparse_unicode_if_low_surrogate_p:n} returns a boolean true or false (i.\,e.\ \macro{\c_true_bool} or \macro{\c_false_bool}).

\begin{macrodef}*
|\jsonparse_unicode_convert_surrogate_pair:nn| {<codepoint>} {<codepoint>}
|\jsonparse_unicode_convert_surrogate_pair:ee| {<codepoint>} {<codepoint>}
\end{macrodef}
The expandable command \macro{\jsonparse_unicode_convert_surrogate_pair:nn} converts a surrogate pair to the relevant Unicode codepoint. The returned value is an integer. It takes as first argument the codepoint of the low surrogate and as second argument the codepoint of the high surrogate. It does not check whether the codepoints actually belong to the relevant ranges of codepoints for high and low surrogates.

\section{Deprecated commands}

The following commands displayed in red boxes on the left have been deprecated and the relevant replacement displayed in the green box right to it should be used. To simplify the representation of the code and clarify how arguments are supposed to be used, numbers are used to identify the arguments.

To ensure backward compatibility, the deprecated commands are still supported, but their use is not recommended.

\subsection{Deprecated user commands}

\begin{macrodeprecated}*
|\JSONParseSetValue|
  {<1>}{<2>}{<3>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseValue|[store in={<1>},
  rescan=false]{<2>}{<3>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\JSONParseSetRescanValue|
  {<1>}{<2>}{<3>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseValue|[store in={<1>},
  rescan]{<2>}{<3>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\JSONParseSetKeys|
  {<1>}{<2>}{<3>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseKeys|
  [store in={<1>}]{<2>}{<3>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\JSONParseSetArrayCount|
  {<1>}{<2>}{<3>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseArrayCount|
  [store in={<1>}]{<2>}{<3>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\JSONParseArrayValues|
  [<1>]{<2>}{<3>}[<4>]{<5>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseArrayUse|
  [<1>]{<2>}{<3>}[<4>]{<5>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\JSONParseArrayValuesMap|
  [<1>]{<2>}{<3>}[<4>]{<5>}
  [<6>][<7>]
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\JSONParseArrayMapFunction|
  [<1>, code before={<6>},
    code after={<7>}]
  {<2>}{<3>}[<4>]{\<5>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\x|{<1>}{<2>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\$|{<1>}{<2>}
\end{macroreplacement}

The command \macro{\JSONParseArrayMapFunction} takes as last argument a command denoting the relevant mapping function including the preceding backslash, while the deprecated command \macro{\JSONParseArrayValuesMap} required the name of this function without preceding backslash.

The commands \macro{\JSONParseSetRescanValue} and \macro{\JSONParseSetKeys} set the relevant token variable locally.

\subsection{Deprecated L3 commands}

\begin{macrodeprecated}*
|\jsonparse_to_prop:Nn|
  <1> {<2>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\jsonparse_gset_parse:Nn|
  <1> {<2>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\jsonparse_to_prop_local:Nn|
  <1> {<2>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\jsonparse_set_parse:Nn|
  <1> {<2>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\jsonparse_filter:Nn|
  <1> {<2>}
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\jsonparse_set_filter:Nn|
  <1> {<2>}
\end{macroreplacement}

\begin{macrodeprecated}*
|\jsonparse_parse_keys:NN|
  <1> <2>
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\jsonparse_set_parse_keys:NN|
  <2> <1>
\end{macroreplacement}

\begin{macrodeprecated}*
|\jsonparse_array_count:NN|
  <1> <2>
\end{macrodeprecated}
\hfill
\begin{macroreplacement}
|\jsonparse_set_array_count:NN|
  <2> <1>
\end{macroreplacement}

Note that the order of the arguments of the commands \macro{\jsonparse_set_parse_keys:NN} is reversed compared to the deprecated command \macro{\jsonparse_parse_keys:NN}. The same holds for the command \macro{\jsonparse_set_array_count:NN} compared to the deprecated command \macro{\jsonparse_array_count:NN}.

% =====

\printchanges

\end{document}

%% End of file `jsonparse-doc.tex`.
