Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am trying to make a command with named (key-value) parameters to produce a table row. The reason is that table has more than 9 columns (command parameters) that will have position changed, be deleted or added. So it is hard to keep it with regular command (both because positions and limited number of args).

I tried to make it work with xkeyval package, but something gets broken inside table. Here is MWE:

\documentclass{article}
\usepackage{xkeyval}
\begin{document}

\makeatletter
\define@key{myrowkey}{name}{\def\MyRowName{#1}}
\define@key{myrowkey}{num}{\def\MyRowNum{#1}}
\makeatother

\newcommand\myrow[1]{
  \setkeys{myrowkey}{#1}
  \MyRowName, \MyRowNum & \\ \hline
}

\newcommand\myrowb[1]{
  \setkeys{myrowkey}{#1}
  \MyRowName & \MyRowNum \\ \hline
}

\begin{table}
  \begin{tabular}{|c|c|}\hline
    A & B \\ \hline
    \myrow{name=Abc,num=2000}
    \myrow{name=Def,num=2000}
  \end{tabular}
\end{table}

\end{document}

Command \myrow works as I'd like it to, while \myrowb does not, i.e., it produces an error. If I replace \def\MyRowName{...} with \newcommand\MyRowName{} and then \renewcommand\MyRowName{#1} there is no error any more, but an empty cell instead of the value (num).

share|improve this question

2 Answers 2

up vote 3 down vote accepted

The definitions are made within the first cell of the tabular and don't survive to the next cell. You need to make their definitions global so they can span multiple columns. If you change \def to \gdef in the key definitions it will work.

enter image description here

\documentclass{article}
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\begin{document}

\makeatletter
\define@key{myrowkey}{name}{\gdef\MyRowName{#1}}
\define@key{myrowkey}{num}{\gdef\MyRowNum{#1}}
\makeatother

\newcommand\myrow[1]{%
  \setkeys{myrowkey}{#1}%
  \MyRowName, \MyRowNum & \\ \hline
}

\newcommand\myrowb[1]{%
  \setkeys{myrowkey}{#1}%
  \MyRowName & \MyRowNum \\ \hline
}

\begin{table}
  \begin{tabular}{|c|c|}\hline
    A & B \\ \hline
    \myrowb{name=Abc,num=2000}
    \myrow{name=Def,num=2000}
  \end{tabular}
\end{table}

\end{document}

Note the use of % to avoid spurious spaces in your definitions of \myrow and \myrowb. See What is the use of percent signs (%) at the end of lines?

share|improve this answer
    
Wow, that was simple :P Thnx! –  Ivan Sep 19 '13 at 17:47
1  
@Ivan: Note that this solution will copy elements from one row to the next if it is not specified in the keys. You could add the defaults to the \setkeys command within \myrowb: \setkeys{name={},num={},#1}. –  Werner Sep 19 '13 at 18:01
    
Yes, I am aware of that. In my full version I have keyreset command for this. –  Ivan Sep 20 '13 at 8:50

Without \gdef; this has the advantage that if you need to omit some entry, you just don't set the key (provided you set up at the beginning an empty value for each key).

\documentclass{article}
\usepackage{xkeyval}

\makeatletter
\define@key{myrowkey}{name}{\def\MyRowName{#1}}
\define@key{myrowkey}{num}{\def\MyRowNum{#1}}

\newcommand\myrow[1]{%
  \setkeys{myrowkey}{#1}%
  \begingroup\protected@edef\x{\endgroup
    \MyRowName, \MyRowNum & 
 }\x \\ \hline
}

\newcommand\myrowb[1]{%
  \setkeys{myrowkey}{#1}%
  \begingroup\protected@edef\x{\endgroup
    \MyRowName & \MyRowNum 
  }\x \\ \hline
}
\makeatother

\begin{document}

\begin{tabular}{|c|c|}\hline
  A & B \\ \hline
  \myrow{name=Abc,num=2000}
  \myrow{name=Def,num=2000}
\end{tabular}

\begin{tabular}{|c|c|}\hline
  A & B \\ \hline
  \myrowb{name=Abc,num=2000}
  \myrowb{name=Def,num=2000}
\end{tabular}

\end{document}

The idea is to expand the key values before TeX “sees” the &.

enter image description here

The same idea implemented in LaTeX3

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\tl_new:N \l_ivan_row_name_tl
\tl_new:N \l_ivan_row_num_tl
\keys_define:nn { ivan/tab }
 {
  name .code:n    = { \tl_set:Nn \l_ivan_row_name_tl { \exp_not:n { #1 } } },
  name .initial:n = {},
  num  .code:n    = { \tl_set:Nn \l_ivan_row_num_tl { \exp_not:n { #1 } } },
  num  .initial:n = {}
 }

\NewDocumentCommand\myrow{m}
 {
  \keys_set:nn { ivan/tab } { #1 }
  \use:x
   {
    \l_ivan_row_name_tl,~\l_ivan_row_num_tl
    & 
   }
  \\ \hline
}

\NewDocumentCommand\myrowb{m}
 {
  \keys_set:nn { ivan/tab } { #1 }
  \use:x
   {
    \l_ivan_row_name_tl & \l_ivan_row_num_tl
   }
  \\ \hline
}
\ExplSyntaxOff

\begin{document}

\begin{tabular}{|c|c|}\hline
  A & B \\ \hline
  \myrow{name=Abc,num=2000}
  \myrowb{name=\textbf{X}} % no num
  \myrowb{name=Def,num=1}
\end{tabular}

\end{document}

As you see, not giving a value will leave the entry empty. Adding keys is made with the same scheme.

enter image description here

share|improve this answer
    
Could you please elaborate what do you mean (and how this code achieves it) by "expanding values before TeX sees the '&'". (I roughly understand what happens in my example, but I am not sure that I understand how you circumvent it.) –  Ivan Sep 20 '13 at 8:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.