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

如何用C#和OpenXML复制Word书签内容并保留格式与图表

用C# + OpenXML复制Word书签内的富内容(含格式、表格、图表)

直接上可运行的解决方案,核心是正确复制书签范围内的所有节点,包括关联的文档部件(比如图表):

完整代码

先确保安装DocumentFormat.OpenXml NuGet包,然后用下面的方法:

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System.Collections.Generic;
using System.Linq;

public static void CopyBookmarkContent(string sourceDocPath, string sourceBookmarkName, string targetDocPath, string targetBookmarkName, string outputPath)
{
    // 先复制目标模板到输出路径,避免修改原文件
    System.IO.File.Copy(targetDocPath, outputPath, overwrite: true);

    // 打开源文档(只读)和输出文档(可编辑)
    using (var sourceDoc = WordprocessingDocument.Open(sourceDocPath, isEditable: false))
    using (var targetDoc = WordprocessingDocument.Open(outputPath, isEditable: true))
    {
        var sourceMainPart = sourceDoc.MainDocumentPart;
        var targetMainPart = targetDoc.MainDocumentPart;

        // 定位源书签的起始和结束节点
        var sourceBookmarkStart = sourceMainPart.Document.Body.Descendants<BookmarkStart>()
            .FirstOrDefault(b => b.Name == sourceBookmarkName);
        var sourceBookmarkEnd = sourceMainPart.Document.Body.Descendants<BookmarkEnd>()
            .FirstOrDefault(b => b.Id == sourceBookmarkStart.Id);

        if (sourceBookmarkStart == null || sourceBookmarkEnd == null)
            throw new System.Exception("找不到源书签");

        // 收集书签内的所有内容节点,深克隆保留格式
        var contentNodes = new List<OpenXmlElement>();
        var currentNode = sourceBookmarkStart.NextSibling();
        while (currentNode != null && currentNode != sourceBookmarkEnd)
        {
            var clonedNode = currentNode.CloneNode(deep: true);
            contentNodes.Add(clonedNode);

            // 处理图表:复制关联的ChartPart到目标文档
            if (clonedNode is Drawing drawing)
            {
                var chartRef = drawing.Descendants<DocumentFormat.OpenXml.Drawing.Charts.ChartReference>().FirstOrDefault();
                if (chartRef != null)
                {
                    var sourceChartPart = (ChartPart)sourceMainPart.GetPartById(chartRef.Id);
                    var targetChartPart = targetMainPart.AddNewPart<ChartPart>();
                    // 复制图表数据
                    sourceChartPart.FeedData(targetChartPart.GetStream());
                    // 更新克隆节点的引用ID,指向目标文档的新ChartPart
                    chartRef.Id = targetMainPart.GetIdOfPart(targetChartPart);
                }
            }

            currentNode = currentNode.NextSibling();
        }

        // 定位目标书签的起始节点
        var targetBookmarkStart = targetMainPart.Document.Body.Descendants<BookmarkStart>()
            .FirstOrDefault(b => b.Name == targetBookmarkName);
        if (targetBookmarkStart == null)
            throw new System.Exception("找不到目标书签");

        // 在目标书签起始位置后插入所有复制的内容
        foreach (var node in contentNodes)
        {
            targetBookmarkStart.Parent.InsertAfter(node, targetBookmarkStart);
        }

        // 保存修改
        targetMainPart.Document.Save();
    }
}

调用示例

// 替换成你的实际路径和书签名称
CopyBookmarkContent(
    sourceDocPath: @"C:\Temp\Source.docx",
    sourceBookmarkName: "ToBeSaved2",
    targetDocPath: @"C:\Temp\Template.docx",
    targetBookmarkName: "ToBeSaved2",
    outputPath: @"C:\Temp\NewVersion.docx"
);

关键注意事项

  • 深克隆节点:用CloneNode(deep: true)才能复制节点的所有子元素和格式属性,不然会丢失字体、段落样式等。
  • 图表单独处理:Word的图表是作为独立的ChartPart存储的,必须把这个部件复制到目标文档,同时更新正文里的引用ID,否则插入后图表无法显示。
  • 保护原模板:先复制目标模板到输出路径再修改,避免破坏原始模板文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:25:30