这里有两个相关但是独立的问题:
- 如何以编程方式引用一个包
- 如何在你的Markdown文档中拥有两个独立的参考文献部分
这两个问题都有解决方案,我将逐一介绍:
如何以编程方式引用一个软件包
关键在于意识到Pandoc只会在R代码块运行之后编写您的文档。这为您提供了在R markdown文档中以编程方式编写.bib
文件的机会,而该文件仅在文档创建阶段由Pandoc读取。
它还取决于能否在参考书目中使用两个.bib
文件。这也是可能的,但我们现在暂时不讨论这个问题。
您需要的是一个函数,该函数将获取软件包名称,获取bibtex格式的引文,将它们全部粘贴在一起并将其保存为.bib
文件。我在这里编写了一个示例函数来展示如何完成这项工作。
此函数必须处理输出多个bibtex引文的软件包,并且会自动在bibtex中插入软件包名称,以便您可以在markdown中使用@packagename引用任何软件包。它使用非标准评估和...
参数,因此您无需对软件包名称进行引用或将它们包装在c()
中:
citeR <- function(...)
{
packages <- unlist(lapply(as.list(match.call()), deparse))[-1]
Rbibs <- ""
for(package in packages)
{
Rbib <- capture.output(print(citation(package), bibtex = T))
Rbib <- mapply(function(x, y) Rbib[x:y],
grep(" @.+[{]", Rbib),
which(Rbib == " }"))
if(class(Rbib) == "matrix"){
Rbib[1, 1] <- gsub(",", paste0(package, ","), Rbib[1, 1])
Rbib <- paste0(Rbib, collapse = "\n")
} else {
Rbib <- unlist(lapply(Rbib, function(x) {
x[1] <- gsub(",", paste0(package, ","), x[1]);
x <- paste0(unlist(x), collapse = "\n")
return(x)
}))
}
if(length(Rbib) > 1) {
if(any(grepl("@Manual", Rbib))) {
Rbib <- Rbib[grep("@Manual", Rbib)][1]
} else {
Rbib <- Rbib[1]}}
Rbibs <- paste(Rbibs, Rbib, sep = "\n\n")
}
writeBin(charToRaw(utf8::as_utf8(Rbibs)), "packages.bib")
}
要使用它,您只需将其放在一个R块中,echo = FALSE,并执行以下操作:
citeR(dplyr, ggplot2, knitr, pROC)
如何拥有两个参考文献部分
这部分的答案不是我写的,我从这里得到了答案。这比第一部分要复杂得多。首先,您必须使用一个lua过滤器,这需要最新版本的rmarkdown和Pandoc,所以请更新到最新版本,否则可能无法正常工作。
提供的链接中描述了使用lua过滤器的基本原理,但是我将在此处包含@tarleb的完整说明。您必须将以下文件保存为multiple-bibliographies.lua
,并保存在与您的markdown相同的目录中:
local all_cites = {}
local doc_meta = pandoc.Meta{}
local function create_topic_bibliography (div)
local name = div.identifier:match('^refs([_%w]*)$')
if not name then
return nil
end
local tmp_blocks = {
pandoc.Para(all_cites),
pandoc.Div({}, pandoc.Attr('refs')),
}
local tmp_meta = pandoc.Meta{bibliography = doc_meta['bibliography' .. name]}
local tmp_doc = pandoc.Pandoc(tmp_blocks, tmp_meta)
local res = pandoc.utils.run_json_filter(tmp_doc, 'pandoc-citeproc')
div.content = res.blocks[2].content
return div
end
local function resolve_doc_citations (doc)
local meta = doc.meta
local orig_bib = meta.bibliography
meta.bibliography = pandoc.MetaList{orig_bib}
for name, value in pairs(meta) do
if name:match('^bibliography_') then
table.insert(meta.bibliography, value)
end
end
doc = pandoc.utils.run_json_filter(doc, 'pandoc-citeproc')
doc.meta.bibliography = orig_bib
return doc
end
return {
{
Cite = function (c) all_cites[#all_cites + 1] = c end,
Meta = function (m) doc_meta = m end,
},
{Pandoc = resolve_doc_citations,},
{Div = create_topic_bibliography,}
}
为了使其正常工作,您的YAML头应该如下所示:
---
title: "Cite R packages"
author: ''
date: "01/02/2020"
output:
pdf_document:
pandoc_args: --lua-filter=multiple-bibliographies.lua
bibliography_software: packages.bib
bibliography_normal: test.bib
---
请注意,在开始编译文档时,
packages.bib
文件不需要存在,因为它将在调用Pandoc之前创建。
要插入参考文献部分,您需要在适当的位置插入这些HTML片段到您的Markdown中。
<div id = "refs_normal"></div>
并且
<div id = "refs_software"></div>
将所有内容组合在一起
我知道这已经是一个很长的答案,但我认为包括一个完整的工作示例并展示PDF输出会很有帮助:
---
title: "Cite R packages"
author: ''
date: "01/02/2020"
output:
pdf_document:
pandoc_args: --lua-filter=multiple-bibliographies.lua
bibliography_software: packages.bib
bibliography_normal: test.bib
---
This is a citation of a paper: @mayer2011.
This is a citation of an R package @dplyr
And another @ggplot2 and another @knitr plus @pROC
\setlength{\parindent}{-0.2in}
\setlength{\leftskip}{0.2in}
\noindent
<div id = "refs_normal"></div>
\setlength{\parindent}{0in}
\setlength{\leftskip}{0in}
\setlength{\parskip}{0pt}
\setlength{\parindent}{-0.2in}
\setlength{\leftskip}{0.2in}
\noindent
<div id = "refs_software"></div>
\setlength{\parindent}{0in}
\setlength{\leftskip}{0in}
\setlength{\parskip}{0pt}
```{r citeR, echo=FALSE}
citeR <- function(...)
{
packages <- unlist(lapply(as.list(match.call()), deparse))[-1]
Rbibs <- ""
for(package in packages)
{
Rbib <- capture.output(print(citation(package), bibtex = T))
Rbib <- mapply(function(x, y) Rbib[x:y],
grep(" @.+[{]", Rbib),
which(Rbib == " }"))
if(class(Rbib) == "matrix")
{
Rbib[1, 1] <- gsub(",", paste0(package, ","), Rbib[1, 1])
Rbib <- paste0(Rbib, collapse = "\n")
}
else
{
Rbib <- unlist(lapply(Rbib, function(x) {
x[1] <- gsub(",", paste0(package, ","), x[1]);
x <- paste0(unlist(x), collapse = "\n")
return(x)
}))
}
if(length(Rbib) > 1)
{
if(any(grepl("@Manual", Rbib)))
{
Rbib <- Rbib[grep("@Manual", Rbib)][1]
}
else
{
Rbib <- Rbib[1]
}
}
Rbibs <- paste(Rbibs, Rbib, sep = "\n\n")
}
writeBin(charToRaw(utf8::as_utf8(Rbibs)), "packages.bib")
}
citeR(dplyr, ggplot2, knitr, pROC)
```
而test.pdf看起来是这样的:
如果您希望自动引用使用的任何软件包,您可以从Markdown文档中对
library()
的任何调用中程序地提取名称。由于实现目标的工作流程有点复杂,您可能需要考虑创建一个小型软件包,其中包含
citeR
函数、lua文档和您自己的
get_lib_citations_from_library_calls("my_markdown.Rmd")
函数来自动完成所有这些操作。
alphabetic
,[alphabetic]
和"alphabetic"
。 - bretauvcsl
文件并没有应用到所有地方。特别是,文本中的引用样式是对应的,但参考文献中却不是。例如,我尝试应用这个csl格式,它在文本中正确地在作者姓名之间添加了“et”,但在参考文献中却没有将“and”替换为“et”(对于两个参考文献都是如此)。你知道如何解决这个问题吗? - bretauv