我用pgfkeys
它来保存格式化参数。树设置了一组默认值以及各种格式的自定义。每个格式都有一个基本定义,而这些定义又可以有多个子格式。我同时维护所有这些,因为我需要能够在单个文档中切换不同的格式和子格式。而且因为我在树中存储了许多参数,所以我不想必须为每个子格式完全定义完整的参数列表。相反,我利用处理程序,以便.search also
我请求特定子格式的参数,并且\pgfkeys
(假设.search also
已正确设置)将提供最具体的自定义,如果没有指定其他设置,则返回默认设置。
例如,对于格式的子格式 1 test one
,我定义了键
\pgfkeys(/stdt/.cd,
test one/1/.search also={/stdt/test one,/stdt/default})
其结果是,如果密钥不存在于该子格式中,我们首先检查父格式,然后检查密钥的默认格式。
然后我使用以下宏来检索默认上下文的正确参数,同时仍允许覆盖某些内容(如果需要):
\NewDocumentCommand{\stdtParameter} { O{\ActiveFormat} O{\theTestSection} m }
{\pgfkeys{/stdt/#1/#2/.cd,#3}}
这在普通情况下可以正常工作,但它很脆弱,当我需要先扩展时就无法使用,例如,如果我想使用该参数作为ifnumcomp
from的参数etoolbox
。
\edef
如果我调用,我可以使用\pgfkeysvalueof
,但不能调用\pgfkeys
其本身。例如,这有效:
\edef\temp{\pgfkeysvalueof{/stdt/\ActiveFormat/num columns}}%
\ifnumgreater{\temp}{1}{Do something}{Do something else}%
但我无法对 做同样的事情\pgfkeys
。我对 和 变体的所有实验\edef
都以失败告终。\pgfkeysvalueof
但是,使用 的问题在于它避开了.search also
处理程序机制,并且未定义的键将返回\relax
,这意味着我需要在自己的宏中重新实现 的所有逻辑.search also
,如果没有必要,我不愿意这样做。
我该如何适当扩展\pgfkeys
以便可以写出这样的内容?
\ifnumgreater{\stdtParameter{num columns}}{1}{Do something}{Do something else}
MWE 显示不同类型呼叫的效果
\documentclass{article}
\usepackage{etoolbox,xparse}
\usepackage{pgfkeys}
\newcommand{\ActiveFormat}{default}
\newcounter{TestSection}
% We need to use cd before getting the parameter because giving the full path
% will stop \pgfkeys from checking search-also trees.
\NewDocumentCommand{\stdtParameter} { O{\ActiveFormat} O{\theTestSection} m }
{\pgfkeys{/stdt/#1/#2/.cd,#3}}
\pgfkeys{/stdt/.cd,
format/.store in=\ActiveFormat,
default/0/.search also={/stdt/default},
default/1/.search also={/stdt/default},
default/name/.initial=Default,
default/my size/.initial=0.5in,
default/my label/.initial=Generic Section,
default/num columns/.initial={1},
test one/.search also={/stdt/default},
test one/name/.initial=Test One,
test one/num columns/.initial={2},
test one/my size/.initial=0.625in,
test one/0/.search also={/stdt/test one,/stdt/default},
test one/1/.search also={/stdt/test one,/stdt/default},
test one/1/my label/.initial=Some Content,
test two/.search also={/stdt/default},
test two/name/.initial=Test Two,
test two/0/.search also={/stdt/test two,/stdt/default},
test two/1/.search also={/stdt/test two,/stdt/default},
test two/my label/.initial=A Different Section
}
\begin{document}
Original format (should be default): \ActiveFormat
Testing \textsf{\textbackslash stdtParameter}
With no optional arguments, the default \textsf{my size} should be \pgfkeys{/stdt/default/my size}.
I got a value of \stdtParameter{my size}.
With one optional argument, \textsf{test one/my size} should be \pgfkeys{/stdt/test one/my size}.
I got a value of \stdtParameter[test one]{my size}.
Now ask for an explicit format which does not define a value for \textsf{my size}. I should get the default value above.
I got a value of \stdtParameter[test two]{my size}
With both optional arguments (format and section), the value of \textsf{test one/1/my label} should be `\pgfkeys{/stdt/test one/1/my label}'.
I got a value of `\stdtParameter[test one][1]{my label}'.
Now check for the fallback label when it's undefined. I asked for \textsf{test two/1/my label}. I should see
`\pgfkeys{/stdt/test two/1/.cd,my label}'.
I got a value of \stdtParameter[test two][1]{my label}.
By default we have \stdtParameter{num columns} columns.
% Switch active formats
\pgfkeys{/stdt/format=test one}
Switched active format to \ActiveFormat, but we're still in section \theTestSection.
The label is `\stdtParameter{my label}'.
\stepcounter{TestSection}
After incrementing the section counter, the label is now `\stdtParameter{my label}' and we
have \stdtParameter{num columns} columns.
% set columns for active format/subformat
\stdtParameter{num columns=3}
Now we have \stdtParameter{num columns} columns.
% The following won't work. We need to fully expand pdfkeys and pass that to \ifnumgreater
% \ifnumgreater{\stdParameter{num columns}}{1}{Multi-column action}{One-column action}
Checking full paths: Default = \pgfkeys{/stdt/default/num columns}.
Test one = \pgfkeys{/stdt/test one/num columns}
Test one, section one = \pgfkeys{/stdt/test one/1/.cd,num columns}
Test two, section one = \pgfkeys{/stdt/test two/1/.cd,num columns}
\end{document}
答案1
答案这个问题给了我解决这个问题所需要的东西。我没有尝试直接从键加载值,而是将它们存储在中间宏中。下面的解决方案扩展了链接的答案,以合并使用.style
来初始化特定格式类型的所有值,并.search also
\documentclass{article}
\usepackage{etoolbox,xparse}
\usepackage{pgfkeys}
\usepackage{multicol}
\usepackage{parskip}
\newcommand{\ActiveFormat}{generic}
\newcommand{\ActiveDomain}{default}
\newcommand{\SectionName}{}
\newcommand{\numcols}{1}
\newcommand{\mysize}{0pt}
\raggedright
\pgfkeys{/stdt/.cd,
format/.store in=\ActiveFormat,
domain/.store in=\ActiveDomain,
name/.store in=\SectionName,
my-size/.store in=\mysize,
num-columns/.store in=\numcols,
% Generic defaults
generic/default/.cd,
.style={/stdt/generic/default/.cd,name,num-columns,my-size},
name/.code=\pgfkeys{/stdt/name=Generic Format},
num-columns/.code=\pgfkeys{/stdt/num-columns=1},
my-size/.code=\pgfkeys{/stdt/my-size=18pt},
% Format one defaults
/stdt/format-one/default/.cd,
.style={/stdt/format-one/default/.cd,name,num-columns,my-size},
name/.code=\pgfkeys{/stdt/name=Format One},
num-columns/.code=\pgfkeys{/stdt/num-columns=2},
my-size/.code=\pgfkeys{/stdt/my-size=36pt},
.search also={/stdt/generic/default},
% Format one domain one
/stdt/format-one/domain-one/.cd,
.style={/stdt/format-one/domain-one/.cd,name,num-columns,my-size},
name/.code=\pgfkeys{/stdt/name={Format One -- Domain One}},
.search also={/stdt/format-one/default,/stdt/generic/default},
% Format two defaults
/stdt/format-two/default/.cd,
.style={/stdt/format-two/default/.cd,name,num-columns,my-size},
name/.code=\pgfkeys{/stdt/name=Format Two},
num-columns/.code=\pgfkeys{/stdt/num-columns=3},
.search also={/stdt/generic/default},
% Format two domain one
/stdt/format-two/domain-one/.cd,
.style={/stdt/format-two/domain-one/.cd,name,num-columns,my-size},
name/.code=\pgfkeys{/stdt/name={Format Two -- Domain One}},
num-columns/.code=\pgfkeys{/stdt/num-columns=4},
.search also={/stdt/format-two/default,/stdt/generic/default},
}
\begin{document}
\pgfkeys{/stdt/\ActiveFormat/\ActiveDomain}
\ifnumgreater{\numcols}{1}{\begin{multicols}{\numcols}}{}
Values with \ActiveFormat/\ActiveDomain:
Name: \SectionName
Columns: \numcols
My Size: \mysize
\ifnumgreater{\numcols}{1}{\end{multicols}}{}
\pgfkeys{/stdt/.cd,format=format-one,domain=default,\ActiveFormat/\ActiveDomain}
\ifnumgreater{\numcols}{1}{\begin{multicols}{\numcols}}{}
Switched to \ActiveFormat/\ActiveDomain.
Name: \SectionName
Columns: \numcols
My Size: \mysize
\ifnumgreater{\numcols}{1}{\end{multicols}}{}
\pgfkeys{/stdt/.cd,format=format-one,domain=domain-one,\ActiveFormat/\ActiveDomain}
\ifnumgreater{\numcols}{1}{\begin{multicols}{\numcols}}{}
Switched to \ActiveFormat/\ActiveDomain.
Name: \SectionName
Columns: \numcols
My Size: \mysize
\ifnumgreater{\numcols}{1}{\end{multicols}}{}
\pgfkeys{/stdt/.cd,format=format-two,domain=domain-one,\ActiveFormat/\ActiveDomain}
\ifnumgreater{\numcols}{1}{\begin{multicols}{\numcols}}{}
Switched to \ActiveFormat/\ActiveDomain.
Name: \SectionName
Columns: \numcols
My Size: \mysize
\ifnumgreater{\numcols}{1}{\end{multicols}}{}
\pgfkeys{/stdt/.cd,format=format-two,domain=default,\ActiveFormat/\ActiveDomain}
\ifnumgreater{\numcols}{1}{\begin{multicols}{\numcols}}{}
Switched to \ActiveFormat/\ActiveDomain.
Name: \SectionName
Columns: \numcols
My Size: \mysize
\ifnumgreater{\numcols}{1}{\end{multicols}}{}
\end{document}
结果: