Task
Consider the following: One needs to store a over time varying amount of pgfkeys entries with a nested data structure. All the entries have the same structure, but the content may vary. So one defines a macro to handle the pgfkeys structure initialization automatically when the user sets the data.
Artificial Example: Inventory (MWE)
\documentclass[parskip=full]{scrreprt}
\usepackage{pgffor}
\usepackage{pgfkeys}
% DESCRIPTION: Set up inventory entries manually
\pgfkeys{
/handlers/.is setter/.code=\pgfkeysedef{\pgfkeyscurrentpath}{%
\noexpand\pgfqkeys{\pgfkeyscurrentpath}{##1}%
},%
/inventory/.cd,
Manual 5 Speed/.is setter,
Manual 5 Speed/inventory id/.initial = XXXXXXXXXX,
Manual 5 Speed/product/.is setter,%
Manual 5 Speed/product/manufacturer/.initial = EMPTY,
Manual 5 Speed/product/product id/.initial = EMPTY,
Manual 6 Speed/.is setter,
Manual 6 Speed/inventory id/.initial = YYYYYYYYYY,
Manual 6 Speed/product/.is setter,%
Manual 6 Speed/product/manufacturer/.initial = EMPTY,
Manual 6 Speed/product/product id/.initial = EMPTY
}
% DESCRIPTION: Logic for creating pgfkey "database" entry automatically and setting them to user specified data
% ARGUMENTS: #1 = entry product, #2 = entry data
\newcommand{\generateEntry}[2]{
% DESCRIPTION: Creating the pgfkeys "family" and intialize with default values
\pgfkeys{
/handlers/.is setter/.code=\pgfkeysedef{\pgfkeyscurrentpath}{%
\noexpand\pgfqkeys{\pgfkeyscurrentpath}{##1}%
},%
/inventory/#1/.cd,
inventory id/.initial = ZZZZZZZZZZ,
product/.is setter,%
product/manufacturer/.initial = EMPTY,
product/product id/.initial = EMPTY
}
% DESCRIPTION: Setting the data to the one specified by the user
\pgfqkeys{/inventory/#1}{#2}
}
% DESCRIPTION: Macro for testing whether it is a problem with wrapping \pgfqkeys in an additional macro
\newcommand{\setEntryData}[2]{
\pgfqkeys{/inventory/#1}{#2}
}
\begin{document}
% DESCRIPTION: Setting the data of the manually added entry
% with \pgfqkeys and "{}" notation
% STATUS: WORKS AS EXPECTED
\pgfqkeys{/inventory/Manual 5 Speed}{
inventory id = 6,
product = {
manufacturer = Herbert Motors,
product id = 433M5
}
}
% DESCRIPTION: Setting the data of the manually added entry
% with \pgfqkeys wrapped in macro and "{}" notation
% STATUS: WORKS AS EXPECTED
\setEntryData{Manual 6 Speed}{
inventory id = 11,
product = {
manufacturer = Herbert Motors,
product id = 433M6
}
}
% DESCRIPTION: Generate and set data for automatic entry
% with "/" notation
% STATUS: WORKS AS EXPECTED
\generateEntry{Automatic 4 Speed}{
inventory id = 21,
product/manufacturer = Jane's Speedshop,
product/product id = JS4A
}
% DESCRIPTION: Generate and set data for automatic entry
% with "{}" notation
% STATUS: FAILS FOR NESTED KEYS
\generateEntry{Automatic 5 Speed}{
inventory id = 42,
product = {
manufacturer = Jane's Speedshop,
product id = JS5A
}
}
% DESCRIPTION: Visualize the data stored in the pgfkeys
\section*{Inventory}
\foreach \entry in {Manual 5 Speed, Manual 6 Speed, Automatic 4 Speed, Automatic 5 Speed}{
\textbf{\entry}:\\
inventory id: \pgfkeysvalueof{/inventory/\entry/inventory id}\\
manufacturer: \pgfkeysvalueof{/inventory/\entry/product/manufacturer}\\
product id: \pgfkeysvalueof{/inventory/\entry/product/product id} \\[0.25cm]
}
\end{document}
This produces the following output:
Issue
When using the {...} notation to set the data of automatically generated entries, the data is not stored (see Automatic 5 Speed in MWE). The / notation seems to work.
What was tried so far
The problem seems to be related to the .is setter pgfkeys handler. It seems like the nested structure is not created, but a single key with e. g. product/manufacturer as id (with the / being interpreted as a letter, not a separator).
So far, the following has been tried:
- Changing
.codeto.ecode - Modifying the expansion from
\noexpandto other possibilities
Those experiments always resulted in errors and the compilation failing.
Question
Is there a simple way to achieve the desired behavior with pgfkeys (e.g. via .is family)?
Suggestions of other methods are also welcome. However, solutions with pgfkeys would be preferred, since the rest of the data handling in the real project is already based upon pgfkeys.
