\chapter[bibtex]{文献管理}

稍微严肃一些的文章，往往会附上一些与文章内容密切相关的参考文献。科研论文更是如此，牛顿都说过自己是站在巨人的肩膀上做事情的。参考文献便是巨人。任何一个 \TeX\ 系统皆不敢对支持参考文献排版这一事宜掉以轻心，否则 \TeX\ 无以为科技文献排版软件之先驱和典范。

\section{数据格式}

大多数 \TeX\ 系统在排版参考文献时，皆需依赖一个名为 bibtex 的外部程序。由 bibtex 基于文献数据文件生成参考文献列表信息，然后交由 \TeX\ 进行排版，这一过程通常是自动进行的，并不需要用户了解和干预。\ConTeXt\ 已在自身内部实现了 bibtex 程序的全部功能，故而不再依赖这个外部程序了。本文档在谈及 Bib\TEX\ 时，主要指文献数据格式。

Bib\TEX\ 文献数据文件是纯文本文件，其中包含着论文、专著和手册等文献数据。例如，一篇期刊论文，其信息可表示为

\starttyping
@article{knuth-1984-literate,
  title={Literate programming},
  author={Knuth, Donald Ervin},
  journal={The computer journal},
  volume={27},
  number={2},
  pages={97--111},
  year={1984},
  publisher={Oxford University Press}
}
\stoptyping

\noindent 再例如一本专著，其信息可表示为

\starttyping
@book{knuth-1986-texbook,
  title={The \TeX\ book},
  author={Knuth, Donald Ervin and Bibby, Duane},
  volume={1993},
  year={1986},
  publisher={Addison-Wesley Reading, MA}
}
\stoptyping

为了学习 \ConTeXt\ 的参考文献排版功能，可将上述文献数据保存到一份空的文本文件里，例如 foo.bib，然后在同一目录下，建立 \CONTEXT\ 源文件 test.tex，其内容为

\starttyping[option=TEX]
\usebtxdataset[foo.bib] % 加载 foo.bib
\starttext
Knuth 基于文学编程\cite[knuth-1984-literate]技术开发了
\TEX\ 系统\cite[knuth-1986-texbook]。
\blank
\placelistofpublications
\stoptext
\stoptyping

\noindent 编译 test.tex，可得以下结果：
% 大概因为 externalfigure 构造的对象没有基线，从而导致其后有一块难以消除的半行留白
% 不得不在前面加上半行空行以达到留白对称的效果。
\blank[halfline]
\externalfigure[14/bibtex-example-01.pdf][width=\textwidth]

若将文献数据文件视为文献数据库，则 bibtex 程序或者 \CONTEXT\ 内部实现的同样功能的模块相当于数据库的搜索引擎。在科研工作中，你可以将自己所读的所有文献置于一份 \type{.bib} 文件中，然后在写论文或专著时，按需引用。

上述示例所用的文献样式是 \ConTeXt\ 默认样式。有三种预定义的文献样式：apa，aps 和 chicago，可在 \type{\placelistofpublications} 之前使用 \type{\usebtxdefinitions} 设定文献样式，例如若使用 aps 样式，只需

\starttyping[option=TEX]
\usebtxdefinitions[aps]
\placelistofpublications
\stoptyping
\blank[halfline]
\externalfigure[14/bibtex-example-02.pdf][width=\textwidth]

预定义的样式，其细节可以调整。例如，以下命令将文献序号宽度设定为 \type{auto}，并将其与文献条目的间距设为半个字宽。

\starttyping[option=TEX]
\setupbtxlist[aps][width=auto,distance=.5em]
\stoptyping
\blank[halfline]
\externalfigure[14/bibtex-example-03.pdf][width=\textwidth]

\section{自制样式}

\ConTeXt\ 提供的这几种文献样式可能并不符合你的要求，此时你有两个方案，第一个方案是放弃这一切，使用 \in[itemcite] 所述的廉价方案，第二个方案是基于 \CONTEXT\ 的文献样式机制，自己定义一种你想要的样式。如果你选择了后者，下文可为你提供一个简单的示例，希望有所帮助。

假设要定义一种名为 bar 的文献样式。首先，按照 \ConTeXt\ 的文件命名约定，创建文件 publ-imp-bar.tex，先写入以下内容：

\starttyping[option=TEX]
\definebtx[bar]
\stoptyping

\noindent 上述代码定义了一个命名空间，其上层还有个空间，即 \type{btx}。然后你可以根据自己需要定义一些子空间。例如，为 \type{bar} 定义子空间 \type{list}，再为后者定义子空间 \type{article}：

\starttyping[option=TEX]
\definebtx[bar:list][bar]
\definebtx[bar:list:article][bar:list]
\stoptyping

\noindent 实际上，子空间通常无需定义，只有当你需要为某个子空间设定外观时才需要定义它。

\type{list} 空间包含了 Bib\TEX\ 数据格式中所有的文献条目和字段名。例如，\type{article} 空间表示期刊论文条目，在该空间内可以定义期刊论文的各种字段空间，例如

\starttyping[option=TEX]
\startsetups btx:bar:list:article
  \texdefinition{btx:bar:list:author}\btxperiod\btxspace
  \texdefinition{btx:bar:list:title}\btxperiod\btxspace
  \texdefinition{btx:bar:list:journal}[J]\btxcomma\btxspace
  \texdefinition{btx:bar:list:year}\btxcomma\btxspace
  \texdefinition{btx:bar:list:volume}
  \texdefinition{btx:bar:list:number}\btxcolon\btxspace
  \texdefinition{btx:bar:list:pages}\btxperiod
\stopsetups
\stoptyping

\noindent 上述代码定义了期刊论文的构成，其中 \type{\btxcomma}，\type{\btxperiod}，\type{\btxcolon}，\type{\btxspace} 分别为西文的逗号，句号，冒号和空格。倘若需要使用中文标点，亦可自行定义，例如：

\starttyping[option=TEX]
\def\btxchinesecomma{，}
\def\btxchineseperiod{．}
\def\btxchinesecolon{：}
\stoptyping

接下来，在 publ-imp-bar.tex 文件中定义期刊论文的各个字段，如下

\starttyping[option=TEX]
\starttexdefinition btx:bar:list:author
  \btxflush{author}
\stoptexdefinition
\stoptyping

\starttyping[option=TEX]
\starttexdefinition btx:bar:list:title
  \color[darkred]{\bf\btxflush{title}}
\stoptexdefinition
\stoptyping

\starttyping[option=TEX]
\starttexdefinition btx:bar:list:journal
  \btxflush{journal}
\stoptexdefinition
\starttexdefinition btx:bar:list:year
    \btxflush{year}
\stoptexdefinition
\starttexdefinition btx:bar:list:volume
    \btxflush{volume}
\stoptexdefinition
\starttexdefinition btx:bar:list:number
  \ignorespaces  % 忽略空白字符
  \btxleftparenthesis  % 左括号 (
  \btxflush{number}
  \btxrightparenthesis  % 右括号 )
\stoptexdefinition
\starttexdefinition btx:bar:list:pages
  \btxflush{pages}
\stoptexdefinition
\stoptyping

上述代码定义了样式 bar 的数据格式，其中 \tex{btxflush} 命令的作用是从 Bib\TEX\ 格式的文献库里获得各条目的字段内容。

若让 \CONTEXT\ 能够按照这种格式将其呈现为文献列表的形式，需要定义一个同名的渲染环境，亦即在 publ-imp-bar.tex 文件中增加以下设定：

\startTEX
\definebtxrendering[bar]
\stopTEX

至此，新的文献样式 bar 便已定义完毕。在 publ-imp-bar.tex 文件所在目录下，建立测试文件 test.tex，其内容如下：

\starttyping[option=TEX]
\usebtxdataset[foo] % 加载 foo.bib
\starttext
Knuth 发明了文学编程语言 WEB\cite[knuth-1984-literate]。
\blank
\usebtxdefinitions[bar]   % 使用上文定义的参考文献列表样式 bar
\placelistofpublications  % 排版文献列表
\stoptext
\stoptyping

\noindent 编译 test.tex，结果如下图。

\blank[halfline]
\externalfigure[14/bibtex-example-04.pdf][width=\textwidth]

\section{样式微调}

上一节定义的 bar 样式，不满足多数中文学术期刊和学位论文的要求，存在的主要问题是，文献序号并非方括号形式且序号与文献条目的间距过大，英文的作者姓名没有将姓放在前面，名字放在后面并缩写。

文献需要的样式可以用 \tex{setupbtxlist} 设定。类似于上文设定 apa 样式的文献序号的方法，将 bar 样式的文献序号设定为方括号形式，并缩小序号与文献条目的间距，只需

\startTEX
\setupbtxlist[bar][starter={[},stopper={]},width=auto,distance=1em]
\stopTEX

\noindent 实际上 \tex{setupbtxlist[bar]} 是 \tex{setuplist[btx:bar]} 的别名，二者是等效的。\tex{setuplist} 命令，我们在 \in[TOC] 节设定目录样式时已经见识过了。

要设置文献条目中的作者信息的样式，需要为其定义命名空间，例如为 bar 样式定义作者信息的命名空间，需作以下定义：

\startTEX
\definebtx[bar:list:author][bar:list]
\stopTEX

\noindent 然后便可设定 \type{bar:list:author} 的外观，如下：

\startTEX
\setupbtx[bar:list:author]
         [authorconversion=invertedshort,
           separator:invertedinitials=\btxspace,
           stopper:initials=\btxspace]
\stopTEX

\noindent 参数 \type{authorconversion} 用于设定作者姓名格式，\type{invertedshort} 可将作者的姓氏前置，名字后置，且该设定只会作用于西文的作者姓名，对中文作者姓名无效，原因是前者的姓名之间有空格作为间隔，有前后之分，而中文的作者姓名之间没有间隔。\type{separator:invertedinitials} 用于设定姓名之间的间隔符，默认是西文逗号。\type{stopper:initials} 用于设定作者姓氏简写字母后的符号，默认是西文句点。

上述样式微调的结果如下图所示：

\blank[halfline]
\midaligned{\externalfigure[14/bibtex-example-fin.pdf][width=\textwidth,frame=on]}

如果你不想为 bar 样式定义作者信息命名空间，也可以直接基于默认的作者信息命名空间设定样式，例如

\startTEX
\setupbtx[default:list:author]
         [authorconversion=invertedshort,
           separator:invertedinitials=\btxspace,
           stopper:initials=\btxspace]
\stopTEX

自定义的文献样式，若未为其定义子命名空间，可以直接用默认的命名空间设定样式，而且这些默认的空间也皆有默认的样式，倘若你不设定，\CONTEXT\ 便按默认的样式渲染该空间表征的文献字段。

\section{更具一般性}

实际上，\CONTEXT\ 文件管理模块为文献数据源提供了别名机制，你可以为载入的文献数据取一个名字，然后基于该名字和文献样式定义渲染环境，最后再将该渲染环境呈现出来，便可得到文献列表，见下例

\startTEX
\usebtxdataset[bibdata][foo.bib]
\setupbtx[dataset=bibdata] % 为 \cite 命令设定数据源
\usebtxdefinitions[bar]    % 载入 bar 样式
\definebtxrendering[references][bar][dataset=demo]
\starttext
Knuth 发明了文学编程语言 WEB\cite[knuth-1984-literate]。
\blank
% 排版文献列表，也可以用 \placebtxrendering[reference]
\placelistofpublications[references]
\stoptext
\stopTEX

\CONTEXT\ 的文献管理功能之所以设计得如此复杂，其意图是要支持同一份文献数据，可以用不同的文献样式排版。不过，我觉得这实在是一种过度设计，可以称得上失败。

\section{第三条路}

如果你对 \CONTEXT\ 的文献管理功能颇为不满，实际上还有第三条路可以走，那就是先用 \CONTEXT\ 内置的文献样式管理引用的文献，待完全定稿后，再手工将文献列表排版成你期望的样式。为了降低工作量，你也可以用现代的一些容易使用的脚本语言编写一个简陋的类似 bibtex 的程序作为辅助工具。

\subject{结语}

Hans Hagen 为 \ConTeXt\ 文献管理功能专门写了一份约 100 页的手册，见

\starttyping
$ mtxrun --search mkiv-publications.pdf
\stoptyping

\noindent 在不理解本文自定义文献样式所用的各命令及其参数的含义时，可从该手册获得更多的理解……只是这份手册内容凌乱，缺乏概观式的介绍，我建议先阅读文档 \cite[bib]，先存下一些不解，然后再阅读该手册。
