8

Is it possible to store the key value argument (a cvs list) to a macro (via \def) and split/further process the content of that macro with \forcsvlist command from etoolbox package?

I want to provide a list of index entries, separated by , such that each entry can be formatted and layout in a special way (as index/glossary, details will still have to be defined).

It is possible (see MWE) to use the \index command directly in the body definition of the \define@key - command within a a \forcvslist statement, leading to some kind of \immediate\write to the index file.

I rather want to process the entries of the cvs list later on, say, in a special command called \MyCmd, saying \forcvslist{\index}{\KVMacroCSVList}, where the \index command may be wrapped by another one expecting the list splitting input as last argument.

However, even the simplified form with \index as argument to \forcsvlist fails with the error message

! Undefined control sequence. \string \indexentry {\KVMacroCSVList }{\thepage } l.47 \MyCmd[IndexList={First,Second}]

Here is my non-working MWE:

\documentclass{book}
\usepackage{etoolbox}
\usepackage{makeidx}
\usepackage{xkeyval}

\makeatletter

\def\KeyFamilyName{SplitListFamily}

\define@key{\KeyFamilyName}{IndexList}[]{%
%Fails to recognize the comma input, does not split!!!
\def\KVMacroIndexList{#1}%
% Generating the index for testing purposes only
\index{#1}%
}%



\define@key{\KeyFamilyName}{CSVList}[]{%
  \def\KVMacroCSVList{#1}%
  \forcsvlist{\index}{#1}% Works 
}%



\newcommand*{\MyCmd}[1][]{%
\setkeys{\KeyFamilyName}{#1}%

% Assume that \KVMacroCSVList is defined 
% Process and format the List%
% However this fails
\forcsvlist{\index}{\KVMacroCSVList}%
}%

\makeatother

\makeindex%
\begin{document}

\chapter{Einstein's theory of relativity}%

\MyCmd[IndexList={First,Second}]

\MyCmd[CSVList={First,Second}]

\printindex
\end{document}

Here is an image that shows the behaviour, if one comments \forcsvlist in \MyCmd. The separate entries stem from the second call to \MyCmd, where as the single line originates from the first call to \MyCmd.

enter image description here

Is it an issue of \expandafter, \protected etc?

Edit

I am not sticking to \forcvslist, another approach will do also.

4
  • 1
    Probably \@xp\forcsvlist\@xp{\@xp\index\@xp}\@xp{\KVMacroCSVList} where \@xp stands for \expandafter.
    – egreg
    Apr 25, 2014 at 12:48
  • @egreg: Yes, that works, but how complicated this looks ;-) I suspected that it has to do with \@xp, even with a double application of it, but not 5 of it ;-)
    – user31729
    Apr 25, 2014 at 14:33
  • \begingroup\edef\x{\endgroup\noexpand\forcsvlist{\noexpand\index}{\unexpanded\expandafter{\KVMacroCSVList}}}\x is not easier.
    – egreg
    Apr 25, 2014 at 14:37
  • @egreg: No, it does not look easier. Will you provide an full answer to 'close' this question?
    – user31729
    Apr 25, 2014 at 14:39

1 Answer 1

6

You have to use

\expandafter\forcsvlist\expandafter
  {\expandafter\index\expandafter}%
  \expandafter{\KVMacroCSVList}

Yes, five of them, because you want to expand the list macro before \forcsvlist acts upon it.

A different approach with expl3:

\documentclass{scrbook}
\usepackage{imakeidx}
\usepackage{xparse}

\makeindex

\ExplSyntaxOn
\NewDocumentCommand{\MyCmd}{ O{} }
 {
  \keys_set:nn { hupfer/index } { #1 }
  \clist_map_inline:Nn \l_hupfer_index_items_clist
   {
    \hupfer_wrap_index:n { ##1 }
   }
 }

\cs_new_protected:Npn \hupfer_wrap_index:n #1
 {
  \index{#1} % for demonstration purposes
 }

\keys_define:nn { hupfer/index }
 {
  IndexList .clist_set:N = \l_hupfer_index_items_clist,
 }
\ExplSyntaxOff

\begin{document}

\chapter{Einstein's theory of relativity}

\MyCmd[IndexList={First,Second}]

\printindex
\end{document}

You must log in to answer this question.