我想我的问题与来自 xparse 的命令在由 \cs_new:Npn? 创建的函数内但我还是不明白发生了什么:在下面的 WE(不是最小的,对此感到抱歉)中,为什么\IfNoValueF
没有检测到-NoValue-
?
\documentclass{article}
\usepackage[margin=0pt,paperheight=5cm]{geometry}
\usepackage{xparse}
\usepackage{datatool}
\ExplSyntaxOn
\DTLnewdb{instrumentsdb}
\cs_new_protected:Nn \mypkg_add_instrument:nnn
{%
\DTLnewrow{instrumentsdb}%
\DTLnewdbentry{instrumentsdb}{status}{#1}%
\DTLnewdbentry{instrumentsdb}{name}{#2}%
\DTLnewdbentry{instrumentsdb}{family}{#3}%
}
\NewDocumentCommand \brass {om}
{
\mypkg_add_instrument:nnn {#1}{#2}{brass}%
}
\NewDocumentCommand \strings {om}
{
\mypkg_add_instrument:nnn {#1}{#2}{strings}
}
\cs_new_protected:Nn \mypkg_display_instrument:nn
{%
#2%
\IfNoValueF {#1} {\\(#1)~(should~appear~only~if~"NoValue"~is~false) }%
}
\NewDocumentCommand \displayinstruments {}
{%
\begin{description}
\item[Brass]\
\begin{itemize}
\DTLforeach*[\DTLiseq{\tl_mypkg_family}{brass}]{instrumentsdb}{%
\tl_mypkg_status=status%
,\tl_mypkg_name=name%
,\tl_mypkg_family=family%
}{%
\item\mypkg_display_instrument:nn {\tl_mypkg_status}{\tl_mypkg_name}%
}
\end{itemize}
%
\item[Strings]\
\begin{itemize}
\DTLforeach*[\DTLiseq{\tl_mypkg_family}{strings}]{instrumentsdb}{%
\tl_mypkg_status=status%
,\tl_mypkg_name=name%
,\tl_mypkg_family=family%
}{%
\item\mypkg_display_instrument:nn {\tl_mypkg_status}{\tl_mypkg_name}%
}
\end{itemize}
\end{description}
}
\ExplSyntaxOff
%
\begin{document}
\brass[new]{trumpet}
\brass[used]{trombone}
%
\strings[used]{guitar}
\strings{violin}
%
\displayinstruments
\end{document}
在https://tex.stackexchange.com/a/94827/18401:
- 建议
\NoValue
在接口转换中测试 ,即在文档级命令的定义范围内。但是,正如我在示例中指出的那样,这会导致代码重复:可以想象有超过\brass
和\strings
需要测试 的文档级命令\NoValue
。 提出了一个替代方案:
\NewDocumentCommand { \foo } { O { } m } { \mypkg_foo:nn {#1} {#2} }
因为我们不关心是否
#1
存在,所以我们只是设置一个空的默认值。但它的“空性”也无法测试,正如以下类似的 WE 所指出的那样。
\documentclass{article}
\usepackage[margin=0pt,paperheight=10cm]{geometry}
\usepackage{xparse}
\usepackage{datatool}
\ExplSyntaxOn
\DTLnewdb{instrumentsdb}
\cs_new_protected:Nn \mypkg_add_instrument:nnn
{%
\DTLnewrow{instrumentsdb}%
\DTLnewdbentry{instrumentsdb}{status}{#1}%
\DTLnewdbentry{instrumentsdb}{name}{#2}%
\DTLnewdbentry{instrumentsdb}{family}{#3}%
}
\NewDocumentCommand \brass {O{}m}
{
\mypkg_add_instrument:nnn {#1}{#2}{brass}%
}
\NewDocumentCommand \strings {O{}m}
{
\mypkg_add_instrument:nnn {#1}{#2}{strings}
}
\cs_new_protected:Nn \mypkg_display_instrument:nn
{%
#2%
\IfNoValueF {#1} {\\(#1)~(should~appear~only~if~"NoValue"~is~false) }%
\tl_if_empty:nF {#1} { \\(#1)~(should~appear~only~if~false~"empty") }%
\tl_if_blank:nF {#1} { \\(#1)~(should~appear~only~if~false~"blank") }%
}
\NewDocumentCommand \displayinstruments {}
{%
\begin{description}
\item[Brass]\
\begin{itemize}
\DTLforeach*[\DTLiseq{\tl_mypkg_family}{brass}]{instrumentsdb}{%
\tl_mypkg_status=status%
,\tl_mypkg_name=name%
,\tl_mypkg_family=family%
}{%
\item\mypkg_display_instrument:nn {\tl_mypkg_status}{\tl_mypkg_name}%
}
\end{itemize}
%
\item[Strings]\
\begin{itemize}
\DTLforeach*[\DTLiseq{\tl_mypkg_family}{strings}]{instrumentsdb}{%
\tl_mypkg_status=status%
,\tl_mypkg_name=name%
,\tl_mypkg_family=family%
}{%
\item\mypkg_display_instrument:nn {\tl_mypkg_status}{\tl_mypkg_name}%
}
\end{itemize}
\end{description}
}
\ExplSyntaxOff
%
\begin{document}
\brass[new]{trumpet}
% \brass[used]{trombone}
%
\strings[used]{guitar}
\strings{violin}
%
\displayinstruments
\end{document}
答案1
为了理解你的代码有什么问题,我添加了一个\tl_show:n
\cs_new_protected:Nn \mypkg_display_instrument:nn
{
\tl_show:n {#1}
#2
\IfNoValueF {#1} {\\(#1)~(should~appear~only~if~"NoValue"~is~false) }
}
这将表明你是不是得到-NoValue-
:#1
你正在得到\tl_mypkg_status
。这正是你所期望的
\mypkg_display_instrument:nn { \tl_mypkg_status } { \tl_mypkg_name }
也许你正在寻求通过值这些变量成立
\mypkg_display_instrument:VV \tl_mypkg_status \tl_mypkg_name
和
\cs_generate_variant:Nn \mypkg_display_instrument:nn { VV }
但请注意,我会非常谨慎地-NoValue-
以你的方式进行存储:它旨在用作文档界面标记,应在内部转换为更合适的形式。例如,由于你存储了某些东西丢失的事实,我更倾向于根本不存储它并在恢复时拾取它。