我如何正确扩展 \pgfkeys?

我如何正确扩展 \pgfkeys?

我用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}}

这在普通情况下可以正常工作,但它很脆弱,当我需要先扩展时就无法使用,例如,如果我想使用该参数作为ifnumcompfrom的参数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}

结果:

测试获取具有和不具有明确键设置的值

相关内容