You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用citeproc-js替换HTML中Pandoc引用生成参考文献遇问题求助

问题修复方案

1. 解决参考文献仅显示最后一项的问题

原因分析

processCitationCluster方法返回的第一个值是更新后的citationsPre数组,它记录了文档中所有已处理的引用上下文。原代码未用该返回值更新全局的citationsPre,导致citeproc无法跟踪全部引用,最终只生成最后一条引用的条目。

修复步骤

调用processCitationCluster后,将全局citationsPre替换为返回结果的第一个元素:

result = citeproc.processCitationCluster(citations, citationsPre, citationsPost);
// 替换原无效的 citationsPre.push(...[])
citationsPre = result[0];

同时移除手动维护的endnoteIndex,直接使用result[1][0][1]返回的citeproc原生编号,避免计数偏差。

2. 解决参考文献URL无法点击的问题

原因分析

citeproc默认输出纯文本格式的参考文献,URL不会自动转为可点击链接,需手动处理每个条目,将URL字符串替换为HTML链接。

修复步骤

生成参考文献HTML前,对每个条目做正则替换,匹配http(s)://开头的URL并转为<a>标签:

const formattedBibEntries = bibResult[1].map(entry => {
  return entry.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank">$1</a>');
});
document.getElementById('bibliography').innerHTML = bibResult[0].bibstart + formattedBibEntries.join('\n') + bibResult[0].bibend;

完整修改后的代码

const regexpGroup = new RegExp(/\[([^\]\n]*@[^\]\n]+)\]/, "g"); // 匹配方括号内的引用组
const regexpRef = new RegExp(/(?<prefix>[^@]*)@(?<id>[^,]+)(,(?<suffix>.*))?/); // 捕获前缀、ID、后缀

const style = document.getElementById('citeproc-csl-style').textContent;
const locale = document.getElementById('citeproc-locale').textContent;
const bibliographyArray = JSON.parse(document.getElementById('citeproc-csl-bib').textContent);
const bibliography = {};
for (const item of bibliographyArray) {
  bibliography[item.id] = item;
}

const citeprocSys = {
  retrieveLocale: function (lang) {
    return locale;
  },
  retrieveItem: function (id) {
    const item = bibliography[id];
    if (!item) throw new Error(`Bibliography item ${id} not found.`);
    return item;
  }
};

const citeproc = new CSL.Engine(citeprocSys, style);

let citationsPre = [];
const citationsPost = []; // 全局维护,无需每次重置

function replacer(match, refsString) {
  const citationItems = refsString.replaceAll('&nbsp;', ' ')
    .split(';')
    .map(refString => {
      const refData = refString.trim().match(regexpRef).groups;
      return {
        id: refData.id,
        prefix: refData.prefix?.trim() || "",
        suffix: refData.suffix?.trim() || ""
      };
    });

  const citationCluster = {
    citationItems: citationItems,
    properties: {
      noteIndex: 0 // 正文引用使用0,脚注引用需递增
    }
  };

  try {
    const result = citeproc.processCitationCluster(citationCluster, citationsPre, citationsPost);
    citationsPre = result[0]; // 更新引用上下文
    // 生成带锚点的引用链接
    const citeNumber = result[1][0][1].replace(/\[|\]/g, '');
    return `<a href="#endnote-${citeNumber}">${result[1][0][1]}</a>`;
  } catch (error) {
    console.warn(error);
    return match;
  }
}

function findReferences(paragraph) {
  paragraph.innerHTML = paragraph.innerHTML.replaceAll(regexpGroup, replacer);
}

// 处理所有段落中的引用
Array.from(document.getElementsByTagName('p')).forEach(findReferences);

// 生成并格式化参考文献
const bibResult = citeproc.makeBibliography();
const formattedBibEntries = bibResult[1].map(entry => {
  // 替换URL为可点击链接
  let formattedEntry = entry.replace(/(https?:\/\/[^\s<>]+)/g, '<a href="$1" target="_blank">$1</a>');
  // 添加锚点,匹配正文引用跳转
  formattedEntry = formattedEntry.replace(/^(\[[0-9]+\])/, '<span id="endnote-$1">$1</span>');
  return formattedEntry;
});

document.getElementById('bibliography').innerHTML = `${bibResult[0].bibstart}${formattedBibEntries.join('\n')}${bibResult[0].bibend}`;

关键改动说明

  • 引用跟踪修复:用processCitationCluster返回的最新citationsPre更新全局变量,确保citeproc能完整记录所有引用。
  • URL链接化:通过正则将纯文本URL转为可点击链接,添加target="_blank"优化跳转体验。
  • 锚点联动:为每个参考文献条目添加对应ID的锚点,实现正文引用到参考文献的精准跳转。
  • 冗余代码清理:移除手动计数的endnoteIndex,直接使用citeproc生成的原生编号,避免逻辑冲突。

内容的提问来源于stack exchange,提问作者rriemann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 01:03:12