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

如何通过OpenXml或Word宏获取Word合同自动生成的条款编号?

解决方案

一、使用Word VBA(宏)获取编号

这是最直接的实现方式,借助Word对象模型可直接读取段落的显示编号:

  • 遍历文档中已用BookmarkStart/BookmarkEnd标记的条款段落
  • 通过Range.ListFormat.ListString属性获取该段落自动生成的编号文本

示例代码:

Sub GetClauseNumbers()
    Dim bmk As Bookmark
    Dim para As Paragraph
    
    For Each bmk In ActiveDocument.Bookmarks
        ' 取书签范围内的第一个条款段落
        Set para = bmk.Range.Paragraphs(1)
        If para.Range.ListFormat.ListType <> wdListNoNumbering Then
            ' 输出书签名称与对应编号,可按需存储或替换文档内的引用占位符
            Debug.Print "书签:" & bmk.Name & ",编号:" & para.Range.ListFormat.ListString
        End If
    Next bmk
End Sub

生成文档后运行该宏,即可获取每个条款的实际编号,再批量替换文档中的引用占位符(比如将{{引用条款ID}}替换为第X.X.X条并添加书签超链接)。

二、使用OpenXml处理

OpenXml本身没有直接获取显示编号的API,需自行解析编号定义与计数逻辑,步骤如下:

  1. 从文档的NumberingDefinitionsPart中读取编号规则(AbstractNum和Num元素)
  2. 对目标段落,读取其ParagraphProperties中的NumberingProperties,获取NumId(编号集ID)和Ilvl(层级)
  3. 匹配对应的NumberingInstance,结合层级计数规则计算实际显示的编号

示例代码片段(C#):

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

public string GetClauseNumber(WordprocessingDocument doc, Paragraph para)
{
    var numProps = para.ParagraphProperties?.NumberingProperties;
    if (numProps == null) return null;
    
    var numId = numProps.NumId?.Val.Value;
    var ilvl = numProps.Ilvl?.Val.Value;
    if (numId == null || ilvl == null) return null;
    
    var numPart = doc.MainDocumentPart.NumberingDefinitionsPart;
    var num = numPart.Numbering.Elements<Num>().First(n => n.NumId.Value == numId);
    var abstractNum = numPart.Numbering.Elements<AbstractNum>().First(an => an.AbstractNumId.Value == num.AbstractNumId.Value);
    
    // 解析层级编号格式与计数,需处理父层级编号拼接、计数重置等场景
    var level = abstractNum.Elements<Level>().First(l => l.LevelIndex.Value == ilvl);
    var numInstance = num.Elements<NumberingInstance>().First();
    var levelOverride = numInstance.Elements<LevelOverride>().FirstOrDefault(lo => lo.LevelIndex.Value == ilvl);
    var currentCount = levelOverride?.StartOverride?.Val.Value ?? 1;
    
    // 完整实现需递归拼接父层级编号,此处为简化示例
    return $"{currentCount}";
}

注意:OpenXml的编号解析逻辑较复杂,需适配不同编号样式、层级继承规则,若非必须使用OpenXml,优先选择VBA方案。

补充说明

  • 若需在生成文档过程中获取编号,建议先生成完整文档并保存后再读取,因为自动编号是Word加载/渲染时计算的,仅构造OpenXml结构阶段无法直接得到最终显示编号。
  • 条款引用可先使用占位符(如[引用:书签名称]),获取编号后再替换为带超链接的正式编号文本。

内容的提问来源于stack exchange,提问作者Filipe Nóbrega

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:54:58