You can exploit expl3
's key-value system and the prop
data type. To turn a key-value list into an expl3
property list you can use \prop_set_from_keyval:Nn
. The function will get each key = value
pair in #2
and add to the prop
list in #1
. A sample document in this case would be:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \defineaspect { mm }
{
\prop_new:c { g__siracusa_#1_aspect_prop }
\prop_gset_from_keyval:cn { g__siracusa_#1_aspect_prop } {#2}
}
%
\tl_new:N \l__siracusa_tmpa_tl
\NewDocumentCommand \getaspect { mm }
{
\prop_get:cnNTF { g__siracusa_#1_aspect_prop } {#2} \l__siracusa_tmpa_tl
{ \tl_use:N \l__siracusa_tmpa_tl }
{ Aspect~#2~does~not~exist~in~#1! }
}
\NewDocumentCommand \fullname { m }
{
{ \getaspect { forename } { .print } \getaspect { forename } {#1} ~ }
{ \getaspect { surname } { .print } \getaspect { surname } {#1} }
}
\ExplSyntaxOff
\defineaspect{forename}{
.print = {},
sherlock = Sherlock,
jim = James
}
\defineaspect{surname}{
.print = \scshape,
sherlock = Holmes,
jim = Moriarty
}
\begin{document}
Did you miss me? --- \fullname{jim}
\end{document}
However this does a one-to-one translation of the input to the data structure. If you need a finer-grained control of that process, say, to differentiate simple keys from key from "special" keys, like .print
, then you could use \keyval_parse:NNn
.
\keyval_parse:NNn
takes two functions and a key-value list as argument. \keyval_parse:NNn
iterates through the key-value list in #3
and uses function #1
or #2
in each item of the list depending if the item has only a key or a key and a value.
A reimplementation of the \defineaspect
above would become:
\prop_new:N \l__siracusa_tmpa_prop
\NewDocumentCommand \defineaspect { mm }
{
\prop_clear:N \l__siracusa_tmpa_prop
\keyval_parse:NNn \__siracusa_aspect:n \__siracusa_aspect:nn {#2}
\prop_new:c { g__siracusa_#1_aspect_prop }
\prop_gset_eq:cN { g__siracusa_#1_aspect_prop } \l__siracusa_tmpa_prop
}
\cs_new_protected:Npn \__siracusa_aspect:n #1
{ \__kernel_msg_error:nnn { kernel } { prop-keyval } {#1} }
\cs_new_protected:Npn \__siracusa_aspect:nn #1#2
{ \prop_put:Nnn \l__siracusa_tmpa_prop {#1} {#2} }
The error message in the definition of \__siracusa_aspect:n
is there only to mimick the behaviour of \prop_set_from_keyval:Nn
, but of course you can change that to the appropriate action when only a key is given.
l3keys
usingunknown .code:n = { ... }
for the keys that aren't know in advance, and normal handling for the other keys?\NewDocumentCommand \defineaspect { mm } { \prop_gset_from_keyval:cn { g_siracusa_#1_aspect_prop } {#2} }
should do what you want.unknown
key were only meant for a custom error message.,
and parsing akey=value
pair,\keyval_parse:NNn
and\ekvparse
(fromexpkv
) do exactly that for you so that you can provide two macros which should be called each element of yourkey=value
list (one if no value was given for an element, one if a value was given).