我对 Latex 还不太熟悉,我正在尝试构建一个自动报告模板。为此,我想定义一个“列表”(我不确定在这种情况下如何称呼它),其中包含许多键/值对的元素,并能够将它们取回。根据我在论坛上看到的示例,我构建了以下内容:
\documentclass{article}
\usepackage{xparse}
\usepackage{forloop}
\ExplSyntaxOn
% Create DosimetryData property
\prop_new:N \l_pollard_DosimetryData_prop
\cs_generate_variant:Nn \prop_put:Nnn { Nx }
% Define DosimetryData add field to token list function
\cs_new_protected:Nn \pollard_add_property:nn
{
\tl_set:Nn \l_pollard_DosimetryData_temp_tl { #1 }
\keys_set:nn { pollard/DosimetryData } { #2 }
}
% Set DosimetryData values
\NewDocumentCommand{\DosimetryData}{m}
{
\prop_set_from_keyval:Nn \l_pollard_DosimetryData_prop { #1 }
\prop_map_inline:Nn \l_pollard_DosimetryData_prop { \pollard_add_property:nn { ##1 } { ##2 } }
}
% Get DosimetryData values
\NewExpandableDocumentCommand{\getDosimetryData}{mm}
{% #1 = node number, #2 = property
\prop_item:Nn \l_pollard_DosimetryData_prop { #1 #2 }
}
% Get DosimetryData number of inputs
\NewDocumentCommand{\getDosimetryDatalength}{}{ \prop_count:N \l_pollard_DosimetryData_prop }
% Define DosimetryData field structure
\keys_define:nn { pollard/DosimetryData }
{
Run .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl Run } { #1 },
DUT .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl DUT } { #1 },
Samples .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl Samples } { #1 },
Energy .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl Energy } { #1 },
Flux .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl Flux } { #1 },
DoseRate .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl DoseRate } { #1 },
TID .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl TID } { #1 },
ProtonFluence .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl ProtonFluence } { #1 },
DDEF .code:n = \prop_put:Nxn \l_pollard_DosimetryData_prop { \l_pollard_DosimetryData_temp_tl DDEF } { #1 },
R .code:n = \keys_set:nn { pollard/DosimetryData } { Run=#1 },
D .code:n = \keys_set:nn { pollard/DosimetryData } { DUT=#1 },
S .code:n = \keys_set:nn { pollard/DosimetryData } { Samples=#1 },
f .code:n = \keys_set:nn { pollard/DosimetryData } { Flux=#1 },
E .code:n = \keys_set:nn { pollard/DosimetryData } { Energy=#1 },
Dr .code:n = \keys_set:nn { pollard/DosimetryData } { DoseRate=#1 },
F .code:n = \keys_set:nn { pollard/DosimetryData } { ProtonFluence=#1 },
}
\ExplSyntaxOff
\newcounter{counter}
\begin{document}
\DosimetryData{
1={DUT = BST182, Run = 1, Samples = 1-6, E = 100, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
2={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
3={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
4={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 }
}
\noindent
DUT 1 -- name: \getDosimetryData{\value{counter}}{DUT}, Run: \getDosimetryData{\value{counter}}{Run}\\
\noindent
DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}\\
\noindent
\text{Length is \getDosimetryDatalength{1}}
\\
\forloop{counter}{1}{\value{counter} < \inteval{4+1}}{
\noindent
Counter: \thecounter, Run: \getDosimetryData{\value{counter}}{Run}\\
}
它有点工作,但只有当我写下元素的编号时我才能获取我的数据,如下所示:
DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}\\
然后,如果我尝试使用计数器或任何“函数”的返回值,它不起作用,我得到一个空白输出:
DUT 1 -- name: \getDosimetryData{\value{counter}}{DUT}, Run: \getDosimetryData{\value{counter}}{Run}\\
我猜是因为当以这种方式调用时,它会检查输入的实际“文本/字符串”而不是“链接”值,但我不知道该怎么做。
然后,我尝试做的另一件事,我猜想它有某种联系,但我无法获取“列表”的大小(即我的示例中的 4)。
我尝试了 prop 和 tl 的 count 函数,但是我不明白返回的数字,它们都不是 4。
我的目标是能够定义这个列表,并能够循环遍历它以获取代码另一部分中的所有元素(基本上是构建一个表格)。
如果有人能帮助我,谢谢!
答案1
我建议拆分您的数据结构。我会将集合名称按顺序排列,并初始化并填充每个数据集的属性列表。
我还改变了您设置剂量测定数据的方式,而不是填充以下使用的属性\keyval_parse:nnn
(如果省略了值,则会引发错误),因此,如果您给出类似的输入,则行为会有所不同\DosimetryData{1={<values>}, 1={<values>}}
,在两种情况下,只有第二个<values>
最终出现在数据结构中,但名称1
将在存储其名称的序列中放置两次。
序列的优点是您不再需要数字名称来循环数据,您只需提供一个\DosimetryDataLoop
使用序列循环所有数据集的宏。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_pollard_DosimetryData_sets_seq
\msg_new:nnn { pollard } { missing-value }
{ Missing~ value~ list~ for~ set~ #1 }
% Set DosimetryData values
\NewDocumentCommand{\DosimetryData}{m}
{
\keyval_parse:nnn
{ \msg_error:nnn { pollard } { missing-value } }
\pollard_add_property:nn
{#1}
}
% Define DosimetryData add field to token list function
\cs_new_protected:Nn \pollard_add_property:nn
{
\seq_put_right:Ne \l_pollard_DosimetryData_sets_seq {#1}
\prop_clear_new:c { l_pollard_DosimetryData_ #1 _prop }
\tl_set:Ne \l_pollard_DosimetryData_temp_tl { #1 }
\keys_set:nn { pollard/DosimetryData } { #2 }
}
\cs_generate_variant:Nn \seq_put_right:Nn { Ne }
\cs_generate_variant:Nn \tl_set:Nn { Ne }
% Get DosimetryData values
\NewExpandableDocumentCommand{\getDosimetryData}{mm}
{% #1 = node number, #2 = property
\prop_item:cn { l_pollard_DosimetryData_ #1 _prop } { #2 }
}
% Get DosimetryData number of inputs
\NewDocumentCommand{\getDosimetryDatalength}{}
{ \seq_count:N \l_pollard_DosimetryData_sets_seq }
\NewDocumentCommand{\getDosimetrySetDatalength}{m}
{ \prop_count:c { l_pollard_DosimetryData_ #1 _prop } }
% Define DosimetryData field structure
\keys_define:nn { pollard/DosimetryData }
{
Run .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Run } {#1},
DUT .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DUT } {#1},
Samples .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Samples } {#1},
Energy .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Energy } {#1},
Flux .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { Flux } {#1},
DoseRate .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DoseRate } {#1},
TID .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { TID } {#1},
ProtonFluence .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { ProtonFluence } {#1},
DDEF .code:n = \prop_put:cnn { l_pollard_DosimetryData_ \l_pollard_DosimetryData_temp_tl _prop } { DDEF } {#1},
R .meta:n = { Run={#1} },
D .meta:n = { DUT={#1} },
S .meta:n = { Samples={#1} },
f .meta:n = { Flux={#1} },
E .meta:n = { Energy={#1} },
Dr .meta:n = { DoseRate={#1} },
F .meta:n = { ProtonFluence={#1} },
}
\NewDocumentCommand \DosimetryDataLoop { +m }
{ \seq_map_inline:Nn \l_pollard_DosimetryData_sets_seq {#1} }
\ExplSyntaxOff
\newcounter{counter}
\begin{document}
\DosimetryData{
1={DUT = BST182, Run = 1, Samples = 1-6, E = 100, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
2={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
3={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 },
4={DUT = BST182, Run = 2, Samples = 1-6, E = 200, f = 3.2e8, DoseRate = 850, TID=100, F = 1e11, DDEF=1e11 }
}
\setcounter{counter}{2}
\noindent
DUT 1 -- name: \getDosimetryData{\the\value{counter}}{DUT}, Run:
\getDosimetryData{\the\value{counter}}{Run}\par
\noindent
DUT 2 -- name: \getDosimetryData{2}{DUT}, Run: \getDosimetryData{2}{Run}
\noindent
{Length is \getDosimetryDatalength, Length of set 1 is
\getDosimetrySetDatalength{1}}
\DosimetryDataLoop
{%
\noindent
Set name: #1, Run: \getDosimetryData{#1}{Run}\par
}
\end{document}