OpenXML Найти заменить текст - PullRequest
0 голосов
/ 22 сентября 2018

Среда

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);
        }
    }

1 Ответ

0 голосов
/ 23 сентября 2018

Примечание. Я хочу избегать использования 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;
}
...