【问题标题】:OpenXML Find Replace TextOpenXML 查找替换文本
【发布时间】:2018-09-22 14:40:09
【问题描述】:

环境

Visual Studio 2017 C#(Word .docx 文件)

问题

查找/替换仅替换“{Today}” - 它无法替换“{ConsultantName}”字段。我检查了文档并尝试使用不同的方法(请参阅注释掉的代码),但没有任何乐趣。

Word 文档只有几段文本 - 文档中没有表格或文本框。我做错了什么?

更新

当我检查 doc_text 字符串时,我可以看到“{Today}”,但“{ConsultantName}”被拆分为多个运行。左大括号和右大括号不和单词在一起——它们之间有 XML 标记:

{</w:t></w:r><w:proofErr w:type="spellStart"/><w:r w:rsidR="00544806"><w:t>ConsultantName</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r w:rsidR="00544806"><w:t>}

代码

    string doc_text = string.Empty;
    List<string> s_find = new List<string>();
    List<string> s_replace = new List<string>();
    // Regex regexText = null;

    s_find.Add("{Today}");
    s_replace.Add("24 Sep 2018");
    s_find.Add("{ConsultantName}");
    s_replace.Add("John Doe");

    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filePath, true))
    {
        // read document
        using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
        {
            doc_text = sr.ReadToEnd();
        }

        // find replace
        for (byte b = 0; b < s_find.Count; b++)
        {
            doc_text = new Regex(s_find[b], RegexOptions.IgnoreCase).Replace(doc_text, s_replace[b]);
            // regexText = new Regex(s_find[b]);
            // doc_text = doc_text.Replace(s_find[b], s_replace[b]);
            // doc_text = regexText.Replace(doc_text, s_replace[b]);
        }

        // update document
        using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
        {
            sw.Write(doc_text);
        }
    }

【问题讨论】:

标签: c# xml openxml docx


【解决方案1】:

注意:我想避免使用 Word Interop。我不想创建 Word 的实例并使用 Word 的对象模型进行查找/替换。

没有办法避免 Word 将文本拆分为多个运行。即使您直接在文档中键入文本、不进行任何更改并且不应用格式,也会发生这种情况。

但是,我通过向文档中添加自定义字段找到了解决问题的方法,如下所示:

  • 打开 Word 文档。转到文件->信息
  • 点击属性标题并选择高级属性
  • 选择自定义标签。
  • 添加您要使用的字段名称并保存。
  • 在文档中单击主菜单上的插入
  • 单击探索快速部件图标并选择字段...
  • 下拉类别并选择文档信息
  • 在字段名称下:选择 DocProperty
  • 在“属性”列表中选择您的自定义字段名称,然后单击确定。

这会将字段插入到您的文档中,即使您应用格式,字段名称也将是完整的,不会被分成多次运行。

更新

为了节省用户手动向文档添加大量自定义属性的繁重任务,我编写了一个使用 OpenXML 的方法。

添加以下用法:

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.CustomProperties;
using DocumentFormat.OpenXml.VariantTypes;

向文档添加自定义(文本)属性的代码:

static public bool RunWordDocumentAddProperties(string filePath, List<string> strName, List<string> strVal)
{
    bool is_ok = true;
    try
    {
        if (File.Exists(filePath) == false)
            return false;                

        using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filePath, true))
        {
            var customProps = wordDoc.CustomFilePropertiesPart;
            if (customProps == null)
            {
                // no custom properties? Add the part, and the collection of properties
                customProps = wordDoc.AddCustomFilePropertiesPart();
                customProps.Properties = new DocumentFormat.OpenXml.CustomProperties.Properties();
            }
            for (byte b = 0; b < strName.Count; b++)
            {
                var props = customProps.Properties;                        
                if (props != null)
                {
                    var newProp = new CustomDocumentProperty();
                    newProp.VTLPWSTR = new VTLPWSTR(strVal[b].ToString());
                    newProp.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
                    newProp.Name = strName[b];

                    // append the new property, and fix up all the property ID values
                    // property ID values must start at 2
                    props.AppendChild(newProp);
                    int pid = 2;
                    foreach (CustomDocumentProperty item in props)
                    {
                        item.PropertyId = pid++;
                    }
                    props.Save();
                }
            }                    
        }
    }
    catch (Exception ex)
    {
        is_ok = false;
        ProcessError(ex);
    }
    return is_ok;
}

【讨论】:

    【解决方案2】:

    你只需要这样做:

    *.csproj

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp3.1</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="DocumentFormat.OpenXml" Version="2.12.3" />
      </ItemGroup>
    
    </Project>
    

    添加这些包:

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

    并将此代码放入您的系统中

    using (WordprocessingDocument wordprocessingDocument =
                WordprocessingDocument.Open(filepath, true))
            {
                var body = wordprocessingDocument.MainDocumentPart.Document.Body;
    
                var paras = body.Elements<Paragraph>();
    
                foreach (var para in paras)
                {
                    foreach (var run in para.Elements<Run>())
                    {
                        foreach (var text in run.Elements<Text>())
                        {
                            if (text.Text.Contains("#_KEY_1_#"))
                            {
                                text.Text = text.Text.Replace("#_KEY_1_#", "replaced-text");
                            }
                        }
                    }
                }
            }
    

    完成

    【讨论】:

    • 所以这不适用于我的word文档。 paras 为空。
    • 尝试使用键#KEY# - 只有单词和#
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 2011-11-24
    • 2021-10-25
    • 2020-08-23
    相关资源
    最近更新 更多