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

如何在修订模式下删除Word文档的段落和Run并保留修订痕迹?

问题解答:在OpenXML中标记Word文档内容为删除(修订模式)

可行性确认

完全可行。通过OpenXML可以实现标记段落或Run为删除,保存后文档中的删除内容会显示删除线,用户接受所有修订时,标记的内容会被彻底移除,完全符合Word修订功能的标准行为。

原代码问题分析

你之前的代码存在两个核心问题:

  1. 直接将Run元素添加到Deleted中,而Deleted的合法子元素是DeletedRun(对应<w:delR>),并非Run,因此触发"Non-composite elements do not have child elements"错误。
  2. 生成的w:del元素未包裹要删除的内容,只是作为段落的子元素存在,导致删除标记未正确关联到目标文本。

正确示例代码

示例1:标记整个段落为删除

using (var document = WordprocessingDocument.Open(@"C:\Data\Test.docx", true))
{
    var mainPart = document.MainDocumentPart;
    // 确保文档开启修订模式
    DocumentSettingsPart settingsPart = mainPart.DocumentSettingsPart ?? mainPart.AddNewPart<DocumentSettingsPart>();
    Settings settings = settingsPart.Settings ?? new Settings();
    
    if (settings.Elements<TrackRevisions>().FirstOrDefault() == null)
    {
        TrackRevisions trackRevisions = new TrackRevisions { Val = new DocumentFormat.OpenXml.OnOffValue(true) };
        settings.AppendChild(trackRevisions);
        settings.Save();
    }

    // 选择要删除的目标段落(此处以第一个段落为例,可根据实际需求修改选择逻辑)
    var targetParagraph = mainPart.Document.Body.Elements<Paragraph>().FirstOrDefault();
    if (targetParagraph != null)
    {
        Deleted deleted = new Deleted
        {
            Author = "Author Name",
            Date = DateTime.Now
        };

        // 将段落所有子元素克隆并移动到Deleted中,再移除原元素
        foreach (var child in targetParagraph.Elements().ToList())
        {
            deleted.AppendChild(child.CloneNode(true));
            child.Remove();
        }

        targetParagraph.AppendChild(deleted);
    }

    mainPart.Document.Save();
}

示例2:标记段落中的指定Run为删除

using (var document = WordprocessingDocument.Open(@"C:\Data\Test.docx", true))
{
    var mainPart = document.MainDocumentPart;
    // 确保文档开启修订模式
    DocumentSettingsPart settingsPart = mainPart.DocumentSettingsPart ?? mainPart.AddNewPart<DocumentSettingsPart>();
    Settings settings = settingsPart.Settings ?? new Settings();
    
    if (settings.Elements<TrackRevisions>().FirstOrDefault() == null)
    {
        TrackRevisions trackRevisions = new TrackRevisions { Val = new DocumentFormat.OpenXml.OnOffValue(true) };
        settings.AppendChild(trackRevisions);
        settings.Save();
    }

    // 选择目标段落和要删除的Run(此处以第一个段落的第一个Run为例)
    var targetParagraph = mainPart.Document.Body.Elements<Paragraph>().FirstOrDefault();
    if (targetParagraph != null)
    {
        var targetRun = targetParagraph.Elements<Run>().FirstOrDefault();
        if (targetRun != null)
        {
            Deleted deleted = new Deleted
            {
                Author = "Author Name",
                Date = DateTime.Now
            };

            // 创建DeletedRun并克隆原Run的内容
            DeletedRun deletedRun = new DeletedRun();
            foreach (var child in targetRun.Elements().ToList())
            {
                deletedRun.AppendChild(child.CloneNode(true));
                child.Remove();
            }

            deleted.AppendChild(deletedRun);
            targetParagraph.AppendChild(deleted);

            // 删除空的原Run(可选,若保留则原Run会为空,不影响显示)
            targetRun.Remove();
        }
    }

    mainPart.Document.Save();
}

生成的正确XML结构示例(删除整个段落)

<w:p>
    <w:del w:author="Author Name" w:date="2024-05-20T10:00:00">
        <w:bookmarkStart w:name="_GoBack" w:id="0"/>
        <w:bookmarkEnd w:id="0"/>
        <w:r>
            <w:t>This is a sentence</w:t>
        </w:r>
    </w:del>
</w:p>

关键注意事项

  • 必须使用Deleted元素包裹要删除的内容,确保删除标记与目标文本关联。
  • 处理Run时,需通过DeletedRun作为Deleted的子元素,不能直接添加原始Run。
  • 修订模式的设置必须调用settings.Save(),否则可能无法生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 01:45:32