我正在为一个俱乐部编写模板/课程,用于会议的官方协议。
因此,我们需要在协议开始时列出与会者的名单,并且在人员离开时,我们需要记录该人员离开(或加入或返回)的时间。
我想要定义 3 个命令\maketableofattendees
, \joins[time]{Name}
, \leaves[time]{Name}
。
参会者表应显示所有参会者的名单,包括他们第一次加入的时间和最后一次离开的时间。
还应该在协议中发生相应动作的位置打印连接和离开(例如发生连接或离开命令的地方)。
我该如何实现这个?
编辑:
输入示例:
\maketableofattendees{Attendees}
\joins[20:00]{Adam}
\joins[20:00]{Bob}
\section{First Topic}
Adam Speaks about a great topic and does a long speech.
First Poll: \attendeecount People Present. Yes: 2, No: 0
\joins[20:15]{Charlie}
\section{Second Topic}
Bob speaks about the second topic.
Second Poll: \attendeecount People Present. Yes: 1, No :2
\leaves[20:30]{Bob}
\section{Third Topic}
Adam speaks about the third topic.
Second Poll: \attendeecount People Present. Yes: 1, No :1
这将产生类似这样的结果:
Attendees:
Adam (From 20:00 to end)
Bob (From 20:00 to 20:30)
Charlie (From 20:15 to end)
#First Topic
Adam Speaks about a great topic and does a long speech.
First Poll: 2 People Present. Yes: 2, No: 0
== 20:15 Charlie enters the Meeting
# Second Topic
Bob speaks about the second topic.
Second Poll: 3 People Present. Yes: 1, No :2
== 20:30 Bob leaves the meeting
# Third Topic
Adam speaks about the third topic.
Second Poll: 2 People Present. Yes: 1, No :1
答案1
可以使用参考文献包。它在 CTAN 上不可用,因此需要手动安装到$TEXMFHOME/tex/latex/rdfref
目录。
我会稍微修改一下你的 TeX 文件:
\documentclass{article}
\usepackage{attendees}
\begin{document}
\maketableofattendees{Attendees}
\maketableofpolls{Polls}
\joins[20:00]{Adam}
\joins[20:00]{Bob}
\topic{First Topic}
Adam Speaks about a great topic and does a long speech.
\poll{First Poll}{2}{0}
% First Poll: \attendeecount People Present. Yes: 2, No: 0
\joins[20:15]{Charlie}
\topic{Second Topic}
Bob speaks about the second topic.
\poll{Second Poll}{1}{2}%: \attendeecount People Present. Yes: 1, No :2
\leaves[20:30]{Bob}
\topic{Third Topic}
Adam speaks about the third topic.
\poll{Third Poll}{1}{1}%: \attendeecount People Present. Yes: 1, No :1
\end{document}
它使用attendees
自定义包,其中包含文档中使用的命令的定义。我添加了一些新命令,即\maketableofpolls
列出使用的投票和主题、\topic
代替使用的命令\section
以及\poll
记录投票名称、投票并打印它们的命令。
这是attendees.sty
包裹:
\ProvidesPackage{attendees}
\RequirePackage{rdfref-user,rdfref-query}
\newcommand\maketableofpolls[1]{%
\section*{#1}%
\Bind{?topic}{rdf:type}{at:topic}{%
\noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par
\Bind{?poll}{at:pollTopic}{?topic}{%
\noindent \quad\GetValProperty{?poll}{at:pollName}. Yes: \GetValProperty{?poll}{at:pollYes}, no: \GetValProperty{?poll}{at:pollNo}\dotfill\GetValProperty{?poll}{doc:pageNo}\par
}
}
}
% \newcommand\at@printpoll
\newcommand\maketableofattendees[1]{%
\section*{#1}%
\Bind{?name}{rdf:type}{at:attendee}{%
% \GetVal prints the variable name, \GetValProperty extracts property from the name
% Set the default left time
\def\at@left{end}%
% use the real at:left if it has been set
\IfProperty{\GetVal{?name}}{at:left}{\def\at@left{\GetValProperty{?name}{at:left}}}{}%
\at@printname{\GetValProperty{?name}{at:name}}{\GetValProperty{?name}{at:joined}}{\at@left}%
}%
}
\newcommand\at@printname[3]{\noindent\textbf{#1}~(From #2 to #3)\par}
\newcommand\topic[1]{%
\section{#1}%
\BlankNode%
\AddProperty{rdf:type}{at:topic}%
\AddPropertyEx{doc:pageNo}{\thepage}% save the page number
\AddProperty{at:topicName}{#1}%
\edef\CurrentTopic{\CurrentObject}% we want to reference the current topic in the poll
}
\newcommand\joins[2][]{%
\WithObject{#2}{%
\AddProperty{rdf:type}{at:attendee}%
\AddProperty{at:name}{#2}%
\AddProperty{at:joined}{#1}%
\AddProperty{is:active}{yes}
}%
}
\newcommand\leaves[2][]{%
\WithObject{#2}{%
\AddProperty{at:left}{#1}%
\AddProperty{is:active}{} % remove the is:active property, so it doesn't pollute next \poll
}%
}
\newcounter{poll@count}
\newcommand\poll[3]{%
\setcounter{poll@count}{0}%
\BlankNode%
\AddProperty{rdf:type}{at:poll}%
\AddPropertyEx{doc:pageNo}{\thepage}%
\AddProperty{at:pollName}{#1}%%
\AddPropertyEx{at:pollTopic}{\CurrentTopic}%
\AddProperty{at:pollYes}{#2}%
\AddProperty{at:pollNo}{#3}%
% process all attendands%
\Bind{?name}{rdf:type}{at:attendee}{%%
% execute the code only on active attendands
\IfProperty{\GetVal{?name}}{is:active}{\stepcounter{poll@count}}{}
}%
\par
\medskip%
\noindent\textbf{#1}: \arabic{poll@count} People Present. Yes: #2, No: #3\par
}%
\AtBeginDocument{%
% reset attendands
\Bind{?name}{rdf:type}{at:attendee}{\SetProperty{\GetVal{?name}}{is:active}{}}
}
\endinput
这里发生了很多事情。rdfref
提供可以设置对象属性的命令。这些属性保存到辅助文件中,因此它们在下一次编译时从文档开头即可使用。这意味着每次对象更改时,文档都需要进行两次编译!
对象有两种类型:命名对象和匿名对象。在我们的示例中,命名对象是可以加入和离开会议的人。以下命令:
\newcommand\leaves[2][]{%
\WithObject{#2}{%
\AddProperty{at:left}{#1}%
\SetProperty{#2}{is:active}{} % remove the is:active property, so it doesn't pollute next \poll
}%
}
将设置人员离开的时间并使该人员处于非活动状态,因此不会在下一次轮询中计算。该\WithObject
命令将人员姓名设置为当前对象标识符,并将属性保存到此对象。
使用了两个属性处理命令。第一个是\AddProperty
,它设置当前对象的属性并将其保存到文件中aux
,这意味着下次编译文档时将恢复此属性,并且从头开始可用。例如,它使我们能够制作参加者列表和民意调查列表。其他类型的属性只是临时的,例如在这种情况下,我们只需要在下一次民意调查计数中禁用此人。我们可以使用命令\SetProperty
。它需要一个明确的对象标识符作为第一个参数。
相反,每个轮询都会创建匿名对象:
\newcommand\poll[3]{%
\setcounter{poll@count}{0}%
\BlankNode%
\AddProperty{rdf:type}{at:poll}%
\AddPropertyEx{doc:pageNo}{\thepage}%
...
创建\BlankNode
一个匿名对象并且后续\AddProperty
命令为其设置属性。\AddPropertyEx
可用于保存宏的扩展值,例如我们例子中的页码。
可以使用以下命令查询属性\Bind
:
\newcommand\maketableofpolls[1]{%
\section*{#1}%
\Bind{?topic}{rdf:type}{at:topic}{%
\noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par
\Bind{?poll}{at:pollTopic}{?topic}{%
\noindent \quad\GetValProperty{?poll}{at:pollName}. Yes: \GetValProperty{?poll}{at:pollYes}, no: \GetValProperty{?poll}{at:pollNo}\dotfill\GetValProperty{?poll}{doc:pageNo}\par
}
}
}
它需要四个参数。前三个是查询,最后一个是在匹配的属性上执行的代码。在本例中,我们首先查找所有主题。对于每个对象,我们设置rdf:type
属性,at:topic
用于主题、at:poll
用于投票和at:attendee
用于与会者。因此,我们需要搜索所有设置rdf:type
为的对象at:topic
:
\Bind{?topic}{rdf:type}{at:topic}{%
参数?topic
是一个变量,它将在第四个参数中包含执行代码中的主题对象标识符。这里我们可以使用以下命令获取对象的各种参数\GetValProperty
:
\noindent\textbf{\GetValProperty{?topic}{at:topicName}}\dotfill\GetValProperty{?topic}{doc:pageNo}\par
在这种情况下,使用主题名称和其起始的页码。
\Bind
命令可以嵌套。要获取某个主题的所有民意调查,我们可以使用以下命令,该命令嵌套在上一个命令中\Bind
:
\Bind{?poll}{at:pollTopic}{?topic}{%
这里使用了两个变量。?topic
是从父绑定设置的,因此它包含当前主题对象。因此,?poll
此命令中只搜索。
\Bind
in 在命令中的另一种用法\poll
是用于计算当前的参加人数:
\Bind{?name}{rdf:type}{at:attendee}{%%
% execute the code only on active attendands
\IfProperty{\GetVal{?name}}{is:active}{\stepcounter{poll@count}}{}
}%
该\IfProperty
命令测试对象是否具有属性。\GetVal
从绑定变量中获取对象标识符。
由于所有属性都设置为辅助文件,因此它们具有与文档末尾相同的值。因此,有必要在文档开始时将所有与会者设置为非活动状态,并仅在命令中启用它们\join
:
\AtBeginDocument{%
% reset attendands
\Bind{?name}{rdf:type}{at:attendee}{\SetProperty{\GetVal{?name}}{is:active}{}}
}
直接\SetProperty
将属性设置为对象。如果值为空,则删除该属性。
结果如下: