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

如何用XSLT 3.0为XML文献引用添加交叉链接?

使用XSLT 3.0为文献引用添加交叉链接

针对你需要给XML中带/不带et al.的文献引用自动添加交叉链接的需求,这里提供一个基于XSLT 3.0的实现方案,核心思路是先预生成文献的匹配规则,再扫描文本替换匹配的引用为链接元素。

假设的输入输出结构

输入XML示例

<document>
  <content>
    <p>参考Smith et al. (2020)的研究,以及Jones (2019)的结论。</p>
    <p>另外,Doe, Smith and Brown (2021)的成果也很重要。</p>
  </content>
  <bibliography>
    <bib id="smith2020">
      <author>Smith, John; Doe, Jane; Brown, Bob</author>
      <year>2020</year>
      <title>XSLT 3.0 Advanced Techniques</title>
    </bib>
    <bib id="jones2019">
      <author>Jones, Alice</author>
      <year>2019</year>
      <title>XML Cross-Reference Methods</title>
    </bib>
    <bib id="doe2021">
      <author>Doe, Jane; Smith, John; Brown, Bob</author>
      <year>2021</year>
      <title>Advanced XML Processing</title>
    </bib>
  </bibliography>
</document>

预期输出XML示例

<document>
  <content>
    <p>参考<xref ref="smith2020">Smith et al. (2020)</xref>的研究,以及<xref ref="jones2019">Jones (2019)</xref>的结论。</p>
    <p>另外,<xref ref="doe2021">Doe, Smith and Brown (2021)</xref>的成果也很重要。</p>
  </content>
  <bibliography>
    <bib id="smith2020">
      <author>Smith, John; Doe, Jane; Brown, Bob</author>
      <year>2020</year>
      <title>XSLT 3.0 Advanced Techniques</title>
    </bib>
    <bib id="jones2019">
      <author>Jones, Alice</author>
      <year>2019</year>
      <title>XML Cross-Reference Methods</title>
    </bib>
    <bib id="doe2021">
      <author>Doe, Jane; Smith, John; Brown, Bob</author>
      <year>2021</year>
      <title>Advanced XML Processing</title>
    </bib>
  </bibliography>
</document>

XSLT 3.0实现代码

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 默认复制所有未匹配的元素和属性 -->
  <xsl:mode on-no-match="shallow-copy"/>

  <!-- 预生成文献引用的匹配规则映射 -->
  <xsl:variable name="bib-ref-map" as="map(xs:string, map(xs:string, xs:string))">
    <xsl:map>
      <xsl:for-each select="//bib">
        <xsl:variable name="authors" select="tokenize(author, '; ')" as="xs:string*"/>
        <!-- 提取作者姓氏(假设作者格式为 "Surname, Firstname") -->
        <xsl:variable name="author-surnames" select="for $a in $authors return replace($a, '^(.*?), .*$', '$1')" as="xs:string*"/>
        <xsl:variable name="year" select="year/text()" as="xs:string"/>
        <xsl:variable name="bib-id" select="@id" as="xs:string"/>

        <xsl:map-entry key="$bib-id">
          <xsl:map>
            <!-- 单作者引用规则:姓氏 + (年份) -->
            <xsl:if test="count($author-surnames) = 1">
              <xsl:map-entry key="single" select="concat($author-surnames[1], ' \(', $year, '\)')"/>
            </xsl:if>
            <!-- 多作者全名引用规则:姓氏1, 姓氏2 and 姓氏3 + (年份) -->
            <xsl:if test="count($author-surnames) &gt; 1">
              <xsl:map-entry key="full" select="concat(
                string-join($author-surnames[position() ne last()], ', '), 
                ' and ', 
                $author-surnames[last()], 
                ' \(', $year, '\)'
              )"/>
            </xsl:if>
            <!-- 多作者et al引用规则:第一作者姓氏 + et al. + (年份) -->
            <xsl:if test="count($author-surnames) &gt; 1">
              <xsl:map-entry key="etal" select="concat($author-surnames[1], ' et al\. \(', $year, '\)')"/>
            </xsl:if>
          </xsl:map>
        </xsl:map-entry>
      </xsl:for-each>
    </xsl:map>
  </xsl:variable>

  <!-- 整理所有匹配规则,按长度倒序排列(优先匹配长格式,避免短规则覆盖长规则) -->
  <xsl:variable name="ref-patterns" as="element()*">
    <xsl:for-each select="map:keys($bib-ref-map)">
      <xsl:variable name="bib-rules" select="$bib-ref-map(.)"/>
      <xsl:for-each select="map:keys($bib-rules)">
        <pattern ref-id="{.}" pattern="{$bib-rules(.)}"/>
      </xsl:for-each>
    </xsl:for-each>
    <xsl:sort select="string-length(@pattern)" order="descending"/>
  </xsl:variable>

  <!-- 处理文本节点,替换匹配的引用为交叉链接 -->
  <xsl:template match="text()">
    <xsl:param name="remaining-text" select="." as="xs:string"/>
    <xsl:if test="$remaining-text">
      <xsl:variable name="matched-rule" as="element(pattern)?" select="$ref-patterns[matches($remaining-text, concat('^.*?(', @pattern, ')'))]"/>
      <xsl:choose>
        <xsl:when test="$matched-rule">
          <!-- 输出匹配前的文本 -->
          <xsl:value-of select="replace($remaining-text, concat('^(.*?)', $matched-rule/@pattern, '.*$'), '$1')"/>
          <!-- 生成带引用的链接元素 -->
          <xref ref="{$matched-rule/@ref-id}">
            <xsl:value-of select="replace($remaining-text, concat('^.*?(', $matched-rule/@pattern, ').*$'), '$1')"/>
          </xref>
          <!-- 递归处理剩余文本 -->
          <xsl:call-template name="text">
            <xsl:with-param name="remaining-text" select="replace($remaining-text, concat('^.*?', $matched-rule/@pattern, '(.*)$'), '$1')"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <!-- 无匹配时直接输出剩余文本 -->
          <xsl:value-of select="$remaining-text"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

关键逻辑说明

  1. 文献规则映射:遍历所有<bib>条目,提取作者姓氏和年份,生成三种引用格式的正则匹配规则(单作者、多作者全名、多作者et al.),并存储在映射中方便快速查找。
  2. 规则排序:将匹配规则按长度倒序排列,确保长格式的全名引用优先被匹配,避免et al.格式提前匹配导致全名引用被遗漏。
  3. 文本递归替换:通过递归扫描文本节点,每次找到第一个匹配的引用规则,将其替换为指定的交叉链接元素(这里用<xref>,你可以根据需求改成<a>或其他元素),然后继续处理剩余文本。
  4. 正则转义:对正则中的特殊字符(如括号、点号)进行转义,确保匹配的准确性。

适配调整

如果你的XML结构和示例不同,只需做以下调整:

  • 若引用文本在特定元素内(如<ref>),将模板匹配改为match="ref/text()"。
  • 若链接元素不是<xref>,替换代码中的<xref>为你需要的元素名称,并调整对应的属性。
  • 若作者格式不是"Surname, Firstname",修改提取姓氏的replace表达式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:25:13