1

I believe I am looking for a LaTeX3 type syntax solution to more appropriately detect a missing argument. To me I would have expected key={} to be a valueless, blank, or empty argument key. After searching through questions I expected \tl_if_blank:nF and IfNoValueF to be my best bet, but either my key variable is not a compatible argument for these functions, or the key has to fail to be produced in order to return a TRUE on these functions. In the MWE below, I can tell it is still being executed because of the extra lines that get included.

I know it would be better if I could avoid including the keys when blank, but at the moment this is out of my control as someone else is responsible for the script that is parsing a database into the content filled syntax block simulated below in \SampleBlock. So I am trying to detect an empty key value but it's not working as I expected.

MWE:

\documentclass[10pt]{article}

\usepackage{xparse}

%--------------------New Commands for consistent formatting ---------------
\ExplSyntaxOn

% define the variable before using it:
\tl_new:N \l_heading_tl
\tl_new:N \l_subheading_tl
\tl_new:N \l_paragraph_tl

% define key:    
\keys_define:nn { Sample }
{
    key-heading                 .tl_set:N = \l_heading_tl
,   key-subheading              .tl_set:N = \l_subheading_tl
,   key-paragraph               .tl_set:N = \l_paragraph_tl
}


\DeclareDocumentCommand{\SampleBlock}{ o }
{
    %TODO some residual debugging may be needed for omitted keys
    \group_begin:% start a group to keep key setting local:
    % set keys if optional argument #1 is given:
    \IfNoValueF {#1} { \keys_set:nn {Sample} {#1} }

    \IfNoValueF{\l_heading_tl}{\noindent\textbf{\l_heading_tl} \\} 
    \IfNoValueF{\l_subheading_tl}{\emph{\l_subheading_tl} \\}    

    \tl_if_blank:nF{\l_paragraph_tl}{\l_paragraph_tl}

    \group_end:
}

\ExplSyntaxOff

%--------------------BEGIN DOCUMENT----------------------
\begin{document}

\SampleBlock[%
key-heading={Title here},
key-subheading={Sub Heading here},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh wait, I could have used lipsum.  Doh!}]   

\medskip \medskip\medskip \medskip\medskip \medskip

\SampleBlock[%
key-heading={No subheading but there will still be a space for it on the next line...},
key-subheading={},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh wait, I could have used lipsum.  Doh!}]   

\end{document}
2

\IfNoValue(TF) is used to test the presence or absence of an o argument. It has nothing to do with checking the emptiness of a token list variable, for which you have to use \tl_if_blank:V(TF). The notation (TF) means you can use TF, T or F (or nothing at all, in some cases, not this one).

Note that \tl_if_blank:nTF { \l_tmpa_tl } would always return false, because the given token list is not blank, as it contains a non space token. When you do

\tl_clear:Nn \l_tmpa_tl
\tl_if_blank:VTF \l_tmpa_tl {TRUE} {FALSE}

would return true.

\documentclass[10pt]{article}

\usepackage{xparse}

%--------------------New Commands for consistent formatting ---------------
\ExplSyntaxOn

% define the variable before using it (not really necessary)
%\tl_new:N \l_engbird_heading_tl
%\tl_new:N \l_engbird_subheading_tl
%\tl_new:N \l_engbird_paragraph_tl

% define key:    
\keys_define:nn { Sample }
 {
  key-heading    .tl_set:N = \l_engbird_heading_tl,
  key-subheading .tl_set:N = \l_engbird_subheading_tl,
  key-paragraph  .tl_set:N = \l_engbird_paragraph_tl,
}

\DeclareDocumentCommand{\SampleBlock}{ O{} }
 {
  %TODO some residual debugging may be needed for omitted keys
  \group_begin:% start a group to keep key setting local:
  % set keys if optional argument #1 is given:
  \keys_set:nn {Sample} {#1}

  \tl_if_blank:VF \l_engbird_heading_tl {\noindent\textbf{\l_engbird_heading_tl} \\} 
  \tl_if_blank:VF \l_engbird_subheading_tl {\emph{\l_engbird_subheading_tl} \\}    

  \tl_if_blank:VF \l_engbird_paragraph_tl {\l_engbird_paragraph_tl}

  \group_end:
 }

\ExplSyntaxOff

%--------------------BEGIN DOCUMENT----------------------
\begin{document}

\SampleBlock[%
key-heading={Title here},
key-subheading={Sub Heading here},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe 
how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh 
wait, I could have used lipsum.  Doh!}]

\bigskip

\SampleBlock[%
key-heading={No subheading but there will still be a space for it on the next line...},
key-subheading={},
key-paragraph={A paragraph of text will go here.  Maybe I will say hello world, maybe I will describe 
how the quick brown fox jumped over the lazy brown dog.  Really, the possibilities are endless.  Oh 
wait, I could have used lipsum.  Doh!}]

\end{document}

Note that \IfNoValueF{#1} for setting keys is redundant: setting no key is as good as doing nothing.


Further notes

You can have three cases for a key, let's call it foo at point of use:

  1. The key is not specified
  2. You specify foo
  3. You specify foo=...

For simplicity, let's assume you always set keys in a group, like in your example. When you define the key with

foo .tl_set:N = \l_whatever_foo_tl,

(or another key definition command), you can add also

foo .initial:n = INITIAL~VALUE,
foo .default:n = DEFAULT~VALUE,

The right-hand sides are empty by default. What's the difference?

  1. The key foo is not set at point of use: the value used for \l_whatever_foo_tl will be INITIAL~VALUE.

  2. The key foo appears without an equals sign: the value used for \l_whatever_foo_tl will be DEFAULT~VALUE.

  3. The user does foo=Something: the value used for \l_whatever_foo_tl will be Something.

Another thing to note: when you have

foo .tl_set:N = \l_whatever_foo_tl,

in \keys_define:nn, the variable in the right-hand side is automatically declared, so it's not necessary to have a \tl_new:N declaration beforehand (but it doesn't harm either).

  • Perhaps note that key = {} is not the same as just key? – Joseph Wright Nov 26 '15 at 9:06
  • @JosephWright There is no key without an equals sign in the example. The key-subheading={} bit can be omitted, as the corresponding token list is empty by default. – egreg Nov 26 '15 at 9:58
  • Yes I know, but the OP is suggesting that key = {} means that no value has been given, whereas it has (an empty value). – Joseph Wright Nov 26 '15 at 10:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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