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'd like to define a new command with optional parameters using the xparse package. Please consider the following example:

\documentclass{minimal}
\usepackage{xparse}

\DeclareDocumentCommand{\mycommand}{ O{mydefault} m o o o }{%
        p:#2%
        \IfNoValueTF{#3}%
            {}%
            { p:#3}%
        \IfNoValueTF{#4}%
            {}%
            { p:#4}%
        \IfNoValueTF{#5}%
            {}%
            { p:#5}
        p:#1
}
\begin{document}
\mycommand[one]{two} \par % p:two p:one
\mycommand[one]{two}[three] \par % p:two p:three p:one
\mycommand[one]{two}[three][four] \par % p:two p:three p:four p:one
\mycommand[one]{two}[three][four][five] \par % p:two p:three p:four p:five p:one
\mycommand[one]{two}[three][][five] \par % p:two p:three p: p:five p:one
\mycommand[one]{two}[][][five] % p:two p: p: p:five p:one
\end{document}

enter image description here

The problem now is that when I'm leaving some parameters empty between two others that are filled in, LaTeX also displays those empty parameters. Applied to the last example I'd like to get p:two p:five p:one.

share|improve this question
3  
@Werner has provided an explanation of the fact that [] is different from an optional argument which is missing. However, I'd point out that runs of optional arguments don't really make for good interface design in most cases. What is the broader context here? –  Joseph Wright Nov 5 '11 at 17:23
1  
I agree, that one optional argument should be enough. If you have more optional arguments, you should use a key=value interface. Even a lot of mandatory arguments are difficult to learn. Nobody wants to learn which of several arguments are optional and which are mandatory and how many optional arguments have to be empty to set the one you want to use. –  Schweinebacke Nov 5 '11 at 17:43
    
@JosephWright I agree with you that this isn't a good interface design but I don't see a better way to achieve the desired result. I'm using the command to refer to acts (e.g. Art. 1 Abs. 2 Ziff. 3 Bst. a XYZ, Art. 1 Bst. a XYZ, ...). And as I'm a lazy guy, it's easier just to write \art{1}[2][3][a]. But if you know a better solution how to handle this please tell it to me. –  Thorsten Nov 5 '11 at 17:43

2 Answers 2

up vote 7 down vote accepted

You have to make an additional comparison on those arguments specified as [], which technically differ from \NoValue. And, you can't just leave them out, since subsequent optional arguments would then be used out-of-sequence. You can use the ifmtarg package:

enter image description here

\documentclass{minimal}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\usepackage{ifmtarg}% http://ctan.org/pkg/ifmtarg
\makeatletter
\DeclareDocumentCommand{\mycommand}{ O{mydefault} m o o o }{%
        p:#2%
        \IfNoValueTF{#3}%
            {}%
            {\@ifmtarg{#3}{}{ p:#3}}%
        \IfNoValueTF{#4}%
            {}%
            {\@ifmtarg{#4}{}{ p:#4}}%
        \IfNoValueTF{#5}%
            {}%
            {\@ifmtarg{#5}{}{ p:#5}}
        p:#1
}
\makeatother
\begin{document}
\mycommand[one]{two} \par % p:two p:one
\mycommand[one]{two}[three] \par % p:two p:three p:one
\mycommand[one]{two}[three][four] \par % p:two p:three p:four p:one
\mycommand[one]{two}[three][four][five] \par % p:two p:three p:four p:five p:one
\mycommand[one]{two}[three][][five] \par % p:two p:three p:five p:one
\mycommand[one]{two}[][][five] % p:two p:five p:one
\end{document}
share|improve this answer

Without other packages, you can define a test yourself

\makeatletter
\def\IfEmptyTF#1{%
  \if\relax\detokenize{#1}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\makeatother
\DeclareDocumentCommand{\mycommand}{ O{mydefault} m O{} O{} O{} }{%
        p:#2%
    \IfEmptyTF{#3}%
            {}%
            { p:#3}%
        \IfEmptyTF{#4}%
            {}%
            { p:#4}%
        \IfEmptyTF{#5}%
            {}%
            { p:#5}
        p:#1
}

The problem is that \NoValue is used if the optional argument is not specified; but [] means "the optional argument is empty".

The test for emptyness is already provided by LaTeX3 packages, so its definition can be changed into

\ExplSyntaxOn
\cs_set_eq:NN \IfEmptyTF \tl_if_blank:nTF
\ExplSyntaxOff
share|improve this answer
    
I'm not sure why both you and @Werner feel the need to define (yet again) empty tests. What's wrong with expl3's \tl_if_blank:nTF? (Your approach also gives a non-expandable test as it can insert a \relax, which if you are using LaTeX3 should therefore be protected.) –  Joseph Wright Nov 5 '11 at 17:19
    
@JosephWright Nothing wrong, but it's not at the same level as \IfNoValueTF, isn't it? And it's not documented in xparse. I believe that xparse should provide a test for emptyness and, maybe, a string equality test. My test for emptyness never leaves a \relax (it's Heiko Oberdiek's, to be honest). –  egreg Nov 5 '11 at 17:22
    
@JosephWright Moreover, \tl_if_blank:nTF can't be used without saying \ExplSyntaxOn, which isn't even mentioned in the documentation of xparse. –  egreg Nov 5 '11 at 17:37

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.