# Return original argument if csname is not defined

For some #1,#2 I define the \csname base:#1:#2\endcsname. Then I define the following

\def\data#1#2{\ifcsname base:#1:#2\endcsname \csname base:#1:#2\endcsname\fi}


and afterwards

\newcommand{\name}[1]{\data{#1}{fname} \data{#1}{lname}}


You can see \data as a 2-dimensional array with information on users with id #1. Now I want to make sure that the original input is printed when the user-id isn't found. I.e. assume I have users john and elvis with full information. Then \name{elvis} will print as Elvis Presley. Now I want #1 printed if \csname base:#1:#2 is not defined, i.e. \name{santa} will print santa since santa is not in my userbase. I tried working with

\ifx\data{#1}{fname}\empty #1\else ...\fi


but couldn't get it to work. How should I do this?

It would be easier to see what you are doing and the best way to answer this with a full minimal working example (MWE), but ignoring this...

The simplest solution would simply be to redefine \data as:

\def\data#1#2{%
\ifcsname base:#1:#2\endcsname \csname base:#1:#2\endcsname%
\else #1%
\fi}


but I suspect that this is not what you want as now \name{santa} will produce santa santa. Instead, I think that you probably want to define something like the following:

\newif\ifDataExists
\newcommand\CheckForData[1]{%
% assuming that fname a reasonable proxy to check for data?
\ifcsname base:#1:fname\endcsname\DataExiststrue
\else\DataExistsfalse
\fi%
}
\newcommand\name[1]{\CheckForData{#1}%
\ifDataExists{#1}{fname} \data{#1}{lname}\else #1\fi}


Now, using your original \data command, \name{santa} will produce a single santa.

• Thanks, exactly what I was looking for. I'll include a MWE the next time, you can consider egreg's first code block as the MWE for this post. Dec 23 '14 at 13:32
\documentclass{article}

\newcommand\data[2]{%
\ifcsname base:#1:#2\endcsname
\csname base:#1:#2\endcsname
\else
#1%
\fi
}
\newcommand{\name}[1]{\data{#1}{fname} \data{#1}{lname}}

% populate one of the databases (I don't know how you do it)
\expandafter\def\csname base:elvis:fname\endcsname{Elvis}
\expandafter\def\csname base:elvis:lname\endcsname{Presley}

\begin{document}

\name{elvis}

\name{santa}

\end{document}


Printing “santa” just once would be possible, but it would also complicate the definition of \name using lower level checks.

If you used my proposed expl3 implementation, just a few modifications would provide a \name macro that has the property you need:

\begin{filecontents*}{\jobname.csv}
id:john1; fname: John; lname: Doe; mail: example@doe.com
id:harry1; fname: Harry; lname: Potter; mail: harry@hogwarts.com
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\storedata}{mm}
{% pass control to an inner function
\konewka_store_data:nn { #1 } { #2 }
}

{
}

\DeclareExpandableDocumentCommand{\getdata}{mm}
{
\konewka_item:nn { #1 } { #2 }
}

\NewDocumentCommand{\listIDs}{}
{% just an example
\seq_use:Nn \g_konewka_id_seq { ,~ }
}

\NewDocumentCommand{\name}{m}
{
\konewka_if_key:nTF { #1 }
{
\konewka_item:nn { #1 } { fname }
\c_space_tl
\konewka_item:nn { #1 } { lname }
}
{
\texttt{#1}
}
}

%%% variables

% we need a colon with the appropriate category code
\tl_const:Nx \c_konewka_colon_tl { \tl_to_str:n {:} }
% other variables
\seq_new:N \g_konewka_id_seq

\tl_new:N \l__konewka_id_tl
\seq_new:N \l__konewka_data_temp_seq
\seq_new:N \l__konewka_field_temp_seq

%%% variants of kernel functions
\cs_generate_variant:Nn \seq_set_split:Nnn { NV , NVV }
\cs_generate_variant:Nn \prop_gput:Nnn { cxx }

%%% our functions

% check if a key is present in the database
\prg_new_conditional:Nnn \konewka_if_key:n { p,T,F,TF }
{
\prop_if_exist:cTF { g_konewka_data_#1_prop }
{
\prg_return_true:
}
{
\prg_return_false:
}
}

% add the new id to a sequence for possible later usage
{
\seq_gput_right:Nn \g_konewka_id_seq { #1 }
}

% the inner function for \storedata
\cs_new_protected:Nn \konewka_store_data:nn
{
% create a property list for an ID
\prop_new:c { g_konewka_data_#1_prop }
% split the second argument at semicolons
\seq_set_split:Nnn \l__konewka_data_temp_seq { ; } { #2 }
% populate the property list
\__konewka_process_entry:n { #1 }
}

% the inner function for \readdata
{
{
% split a line into fields
\seq_set_split:Nnn \l__konewka_data_temp_seq { ; } { ##1 }
% retrieve the first field (ID)
\seq_pop_left:NN \l__konewka_data_temp_seq \l__konewka_id_tl
% split at colon and set the ID to the second part
\seq_set_split:NVV \l__konewka_data_field_seq \c_konewka_colon_tl \l__konewka_id_tl
\tl_set:Nx \l__konewka_id_tl { \seq_item:Nn \l__konewka_data_field_seq { 2 } }
% add the id to the list
% populate the property list
\__konewka_process_entry:V \l__konewka_id_tl
}
}

% syntactic sugar
\cs_new:Npn \konewka_item:nn #1 #2
{% just retrieve the property from the appropriate property list
\prop_item:cn { g_konewka_data_#1_prop } { #2 }
}

% auxiliary function
\cs_new_protected:Nn \__konewka_process_entry:n
{
\seq_map_inline:Nn \l__konewka_data_temp_seq
{
\seq_set_split:NVn \l__konewka_data_field_seq \c_konewka_colon_tl { ##1 }
\prop_gput:cxx { g_konewka_data_#1_prop }
{ \seq_item:Nn \l__konewka_data_field_seq { 1 } }
{ \seq_item:Nn \l__konewka_data_field_seq { 2 } }
}
}
\cs_generate_variant:Nn \__konewka_process_entry:n { V }

\ExplSyntaxOff

\storedata{uthor1}{fname: Algernon; lname: Uthor; mail: a.uthor@tex.org}
\storedata{riter1}{fname: Walter; lname: Riter; mail: w.riter@latex.org}

\begin{document}

\begin{tabular}{cccc}
Id & fname & lname & mail \\
\hline
\texttt{john1} & \getdata{john1}{fname} & \getdata{john1}{lname} & \getdata{john1}{mail} \\
\texttt{harry1} & \getdata{harry1}{fname} & \getdata{harry1}{lname} & \getdata{harry1}{mail} \\
\texttt{uthor1} & \getdata{uthor1}{fname} & \getdata{uthor1}{lname} & \getdata{uthor1}{mail} \\
\texttt{riter1} & \getdata{riter1}{fname} & \getdata{riter1}{lname} & \getdata{riter1}{mail} \\
\end{tabular}

\medskip

The IDs are: \listIDs

\medskip

Print names: \name{john1}'' and \name{santa}''

\end{document}


• Thanks, I'd figured this out as well. Is it possible to work out the solution for printing santa just once? Dec 23 '14 at 13:04
• I might be tempted to use \csname base:#1:#2\expandafter\endcsname just in case something odd gets stored. Dec 23 '14 at 13:10
• How about \newcommand\data[2]{% \ifcsname base:#1:#2\endcsname \csname base:#1:#2\endcsname \else \def\fname{#1} \def\lname{} \csname#2\endcsname% \fi } Dec 23 '14 at 13:12
• Thanks, I had chosen the other implementation from the other post, but I think I'm all going do it in l3. Until then I'm going to use Andrews solution Dec 23 '14 at 13:31