使用OpenXML库替换docx文档(Word文档)中的特定字段

这篇具有很好参考价值的文章主要介绍了使用OpenXML库替换docx文档(Word文档)中的特定字段。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在批量生成Word文档的应用中,最常见的需求莫过于替换掉文档中的特定字段以生成新的文档。利用OpenXML库可轻松实现这一需求。

仅限文本内容的不完善版本

首先放出最简单然而有bug的版本:

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

//使用OpenXml SDK 2.5打开Word文档,并将里面的目标字段替换成指定的值
WordprocessingDocument wordDoc = WordprocessingDocument.Open("word.docx", true);
var body = wordDoc.MainDocumentPart!.Document.Body;
var paras = body!.Elements<Paragraph>();
foreach (var para in paras)
{
    var runs = para.Elements<Run>();
    foreach (var run in runs)
    {
        var texts = run.Elements<Text>();
        foreach (var text in texts)
        {
            if (text.Text.Contains("首席针头"))
            {
                text.Text = text.Text.Replace("首席针头", "吃席针头");
            }
        }
    }
}
//保存文档
wordDoc.Save();
//释放资源
wordDoc.Dispose();

该版本的原理是遍历word文档中的每个段落,搜索段落中的每个文字字段对象,如果找到匹配的值就将其替换成目标值。

该操作存在问题在于有时候看起来连在一起的文字对象是存储在不同的文字字段对象(run)中的(分开的原因大概率是格式不统一,但有时看着格式完全一样也会被分开,魔性),比如下面的文档:

使用OpenXML库替换docx文档(Word文档)中的特定字段

“首席针头”这个词组就被分开成“首席”和“针头”两个不同的文字字段对象进行存储。在这种情况下遍历对象时就无法实现特定字段的匹配。

仅限文本内容的完善版本

要解决这个问题也不难,特定字段可能被分开,我们就将段落里面的所有字段记录下来,然后合并起来看看是否包含该字段。如果是,则检测特定字段在哪几个run中,然后将这几个run合并起来,最后再进行特定字段的替换即可。代码如下:

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using static System.Net.Mime.MediaTypeNames;
using System.Text;
using Text = DocumentFormat.OpenXml.Wordprocessing.Text;



//合并目标范围内的run
void mergeRuns(IEnumerable<Run> runs, string[] copy_text)
{
    //找到特定字段所在的第一个run的位置
    int start = 0;
    while (true)
    {
        string sub_str = "";
        for (int i = start; i < runs.Count(); i++)
        {
            sub_str += copy_text[i];
        }
        if (!sub_str.Contains("首席针头"))
        {
            start--;
            break;
        }
        else
        {
            start++;
        }
    }
    //找到特定字段所在的最后一个run的位置
    string inner_str = "";//范围内的字符串
    int end = runs.Count();
    while (true)
    {
        string sub_str = "";
        for (int i = start; i < end; i++)
        {
            sub_str += copy_text[i];
        }
        if (!sub_str.Contains("首席针头"))
        {
            end++;
            break;
        }
        else
        {
            inner_str = sub_str;
            end--;
        }
    }
    //将范围内的run合并在一起
    int sel_pt = 0;
    foreach (var run in runs)
    {
        if (sel_pt == start)
        {
            var texts = run.Elements<Text>();
            //将run里面的文字改为inner_str的内容
            int num = 0;
            foreach (var mytext in texts)
            {
                if (num == 0)
                {
                    mytext.Text = inner_str;
                }
                else
                {
                    mytext.Text = "";
                }
                num++;
            }
        }
        else if (sel_pt > start && sel_pt < end)//将多余的runs清空
        {
            var texts = run.Elements<Text>();
            foreach (var mytext in texts)
            {
                mytext.Text = "";
            }
        }
        sel_pt++;
    }
}

void replaceTextInParas(IEnumerable<Paragraph> paras)
{
    //遍历文本的所有段落
    foreach (var para in paras)
    {
        while (true)
        {
            var runs = para.Elements<Run>();
            string[] copy_text = new string[runs.Count()];
            int pt = 0;
            foreach (var run in runs)
            {
                var texts = run.Elements<Text>();
                //第一遍先遍历,把run内部的目标字段替换掉,并构建数组记录下所有的run
                //创建长度和texts个数一样的数组,用于记录每个text的内容
                foreach (var text in texts)
                {
                    if (text.Text.Contains("首席针头"))
                    {
                        text.Text = text.Text.Replace("首席针头", "吃席针头");
                    }
                    copy_text[pt] += text.Text;
                }
                pt++;
            }
            //将字符串拼接在一块,看看是否存在目标字段
            string str = string.Join("", copy_text);

            //如果存在目标字段,则将范围内的run合并在一起,然后再替换一次,直到不存在目标字段
            if (str.Contains("首席针头"))
            {
                mergeRuns(runs, copy_text);
            }
            else
            {
                break;
            }
        }
    }
}

//文档读取
WordprocessingDocument wordDoc = WordprocessingDocument.Open("word.docx", true);
//获取文档的主体
var body = wordDoc.MainDocumentPart!.Document.Body;
//获取文档的所有段落
var paras = body!.Elements<Paragraph>();
//替换文档段落中的目标字段
replaceTextInParas(paras);
//保存文档
wordDoc.Save();
//释放资源
wordDoc.Dispose();

文本内容+表格内容的完善版本

当然,该版本仅限于文本内容,对于表格中的内容是无法替换的,原因在于我们在遍历替换的时候并没有遍历表格中的段落。遍历表格中的单元格段落写起来很简单,完整代码如下:

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using static System.Net.Mime.MediaTypeNames;
using System.Text;
using Text = DocumentFormat.OpenXml.Wordprocessing.Text;

//合并目标范围内的run
void mergeRuns(IEnumerable<Run> runs, string[] copy_text)
{
    //找到特定字段所在的第一个run的位置
    int start = 0;
    while (true)
    {
        string sub_str = "";
        for (int i = start; i < runs.Count(); i++)
        {
            sub_str += copy_text[i];
        }
        if (!sub_str.Contains("首席针头"))
        {
            start--;
            break;
        }
        else
        {
            start++;
        }
    }
    //找到特定字段所在的最后一个run的位置
    string inner_str = "";//范围内的字符串
    int end = runs.Count();
    while (true)
    {
        string sub_str = "";
        for (int i = start; i < end; i++)
        {
            sub_str += copy_text[i];
        }
        if (!sub_str.Contains("首席针头"))
        {
            end++;
            break;
        }
        else
        {
            inner_str = sub_str;
            end--;
        }
    }
    //将范围内的run合并在一起
    int sel_pt = 0;
    foreach (var run in runs)
    {
        if (sel_pt == start)
        {
            var texts = run.Elements<Text>();
            //将run里面的文字改为inner_str的内容
            int num = 0;
            foreach (var mytext in texts)
            {
                if (num == 0)
                {
                    mytext.Text = inner_str;
                }
                else
                {
                    mytext.Text = "";
                }
                num++;
            }
        }
        else if (sel_pt > start && sel_pt < end)//将多余的runs清空
        {
            var texts = run.Elements<Text>();
            foreach (var mytext in texts)
            {
                mytext.Text = "";
            }
        }
        sel_pt++;
    }
}

void replaceTextInParas(IEnumerable<Paragraph> paras)
{
    //遍历文本的所有段落
    foreach (var para in paras)
    {
        while (true)
        {
            var runs = para.Elements<Run>();
            string[] copy_text = new string[runs.Count()];
            int pt = 0;
            foreach (var run in runs)
            {
                var texts = run.Elements<Text>();
                //第一遍先遍历,把run内部的目标字段替换掉,并构建数组记录下所有的run
                //创建长度和texts个数一样的数组,用于记录每个text的内容
                foreach (var text in texts)
                {
                    if (text.Text.Contains("首席针头"))
                    {
                        text.Text = text.Text.Replace("首席针头", "吃席针头");
                    }
                    copy_text[pt] += text.Text;
                }
                pt++;
            }
            //将字符串拼接在一块,看看是否存在目标字段
            string str = string.Join("", copy_text);

            //如果存在目标字段,则将范围内的run合并在一起,然后再替换一次,直到不存在目标字段
            if (str.Contains("首席针头"))
            {
                mergeRuns(runs, copy_text);
            }
            else
            {
                break;
            }
        }
    }
}

//文档读取
WordprocessingDocument wordDoc = WordprocessingDocument.Open("word.docx", true);
//获取文档的主体
var body = wordDoc.MainDocumentPart!.Document.Body;
//获取文档的所有段落
var paras = body!.Elements<Paragraph>();
//替换文档段落中的目标字段
replaceTextInParas(paras);

//获取文档的所有表格
var tables = body!.Elements<Table>();
//遍历表格
foreach (var table in tables)
{
    //获取表格的所有行
    var rows = table.Elements<TableRow>();
    //遍历行
    foreach (var row in rows)
    {
        //获取行的所有单元格
        var cells = row.Elements<TableCell>();
        //遍历单元格
        foreach (var cell in cells)
        {
            //获取单元格的所有段落
            var cell_paras = cell.Elements<Paragraph>();
            //替换单元格段落中的目标字段
            replaceTextInParas(cell_paras);
        }
    }
}

//保存文档
wordDoc.Save();
//释放资源
wordDoc.Dispose();

到此,我们就完美解决了docx文档(Word文档)中特定字段的替换问题啦。文章来源地址https://www.toymoban.com/news/detail-508533.html

到了这里,关于使用OpenXML库替换docx文档(Word文档)中的特定字段的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【python】使用docx获取word文档的标题等级、大纲等级和编号等级

    在Microsoft Word中: 【标题X】是一个样式,一般来说,【标题1】样式的大纲级别是1级。 大纲级别一般用于页面导航和生成目录。可以右键文字-段落里查看/设置大纲的级别。设置成【x级】后左侧导航栏就会显示。 编号等级就是大家熟知的项目编号,常用于正文。 基本没有一

    2024年02月03日
    浏览(30)
  • Java使用spire进行word文档的替换

    今天遇到一个需求,需要对word模板进行替换制定的变量 在网上找了很多方案,做了很多的demo,下面就把我觉得比较简单的一种分享给大家 本次的主角是:spire.doc Spire.Doc for .NET 是一款专门对 Word 文档进行操作的 .NET类库。这款控件的主要功能在于帮助开发人员轻松快捷高效

    2024年02月05日
    浏览(28)
  • Node.js 使用 officecrypto-tool 读取加密的 Excel (xls, xlsx) 和 Word( docx)文档

    Node.js 使用 officecrypto-tool 读取加密的 Excel (xls, xlsx) 和 Word( docx)文档, 还支持 xlsx 和 docx 文件的加密(具体使用看文档)。暂时不支持doc文件的解密 传送门:officecrypto-tool 读取加密的 Excel 示例 读取加密的 Word 示例 使用:mammoth officecrypto-tool 使用其他的word读取库也是一样的道理

    2024年02月10日
    浏览(33)
  • 【word】【python】图片字段替换

    在 Word 文档中添加一个特殊的标记(例如:{image_placeholder}),这将充当图片占位符。 使用 python-docx 库打开 Word 文档。 查找占位符并替换为图片。 保存更改后的 Word 文档。 将 your_word_document.docx 替换为包含占位符的 Word 文档的文件名,将 your_image.png 替换为要插入的图片的文

    2024年02月13日
    浏览(37)
  • Python+docx实现python对word文档的编辑

            该模块可以通过python代码来对word文档进行大批量的编辑。docx它提供了一组功能丰富的函数和方法,用于创建、修改和读取Word文档。下面是 docx 模块中一些常用的函数和方法的介绍: 安装:pip install docx                  通过遍历  doc.paragraphs  来获取文档中

    2024年02月16日
    浏览(30)
  • python之python-docx:操作 office word 文档

    在Python中,有一个名为 python-docx 的库,它提供了丰富的功能,可以方便地创建、修改和读取Word文档。 本文将详细介绍 python-docx 库的使用,并提供一些示例来演示其中的功能。为了更好地理解,我们将分为以下几个方面进行讨论: 安装 python-docx 创建和保存Word文档 修改现有

    2024年02月12日
    浏览(26)
  • Python 实现 PDF 到 Word 文档的高效转换(DOC、DOCX)

    PDF(Portable Document Format)已成为一种广泛使用的电子文档格式。PDF的主要优势是跨平台,可以在不同设备上呈现一致的外观。然而,当我们需要对文件内容进行编辑或修改,直接编辑PDF文件会非常困难,而且效果也不理想。将PDF文件转换为Word文档(doc、docx)再进行编辑是一

    2024年02月03日
    浏览(42)
  • 借助文档控件Aspose.Words,将 Word DOC/DOCX 转换为 TXT

    在文档处理领域,经常需要将 Word 文档转换为更简单的纯文本格式。无论是出于数据提取、内容分析还是兼容性原因,将 Word(.doc、.docx)文件转换为纯文本(.txt)的能力对于开发人员来说都是一项宝贵的技能。在这篇博文中,我们将探讨如何在 C# 应用程序中将 Word 文档转换

    2024年01月19日
    浏览(41)
  • 开源Word文字替换小工具更新 增加文档页眉和页脚替换功能

    ITGeeker技术奇客发布的开源Word文字替换小工具更新到v1.0.1.0版本啦,现已支持Office Word文档页眉和页脚的替换。 同时ITGeeker技术奇客修复了v1.0.0.0版本因替换数字引起的in ‘ requires string as left operand, not int错误。 开源Word文字替换小工具官方介绍页面:https://www.itgeeker.net/itgeeke

    2024年02月11日
    浏览(32)
  • word文档批量生成工具(附免费软件)(按Excel表格内容自动替换内容生成文档)

    批量生成word文档是让人无比厌恶但有时又不得不做的事情。比如学校要给拟录取的学生发通知书,就可能需要批量生成一批只有“姓名”、“学院”和“专业”不同,其他内容都相同的word文档以供打印(事实上直接生成pdf是更好的选择,这个以后有心情可以弄一下)。 要实

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包