C # Word Document Замените обычный текст на поле слияния - PullRequest
0 голосов
/ 11 мая 2018

У меня есть шаблон текстового документа и CSV, с которым я хотел бы отправить его по почте.

В текстовом документе у меня есть текст, окруженный << >>, если я хочу использовать его для mailmerge,это соответствует заголовкам в моем CSV.Например, у меня есть <<Salutation>> в моем документе слова и имя поля Приветствие в моем CSV.

Есть ли простой способ заменить текст, окруженный << >>, полем mailmerge, соответствующим его заголовку в CSV?

Код, который у меня есть для чтения данных вэто:

Microsoft.Office.Interop.Word.Application _wordApp = new Microsoft.Office.Interop.Word.Application();
        Microsoft.Office.Interop.Word.Document oDoc = _wordApp.Documents.Add(@"C:\Eyre\Template.docx");
        _wordApp.Visible = true;
        oDoc.MailMerge.MainDocumentType = Microsoft.Office.Interop.Word.WdMailMergeMainDocType.wdFormLetters;
        oDoc.MailMerge.OpenDataSource(@"C:\Eyre\CSV.csv", false, false, true);

        oDoc.MailMerge.Destination = Microsoft.Office.Interop.Word.WdMailMergeDestination.wdSendToNewDocument;
        oDoc.MailMerge.Execute(false);
        Microsoft.Office.Interop.Word.Document oLetters = _wordApp.ActiveDocument;
        oLetters.SaveAs2(@"C:\Eyre\letters.docx",
             Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocumentDefault);

Любая помощь будет высоко ценится

--- EDIT ---

Это, кажется, смущает некоторых людей.У меня есть текстовый шаблон с простым текстом, таким как Salutation, и мне нужна программа на C #, которая заменит этот простой текст полем слияния из CSV.

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Вот версия кода на C # для замены «заполнителей» в документе Word полями слияния. (Для читателей, ищущих VB-версию, см. https://stackoverflow.com/a/50159375/3077495.)

Мой код использует уже запущенный экземпляр Word, поэтому интересующая вас часть начинается с foreach (Word.MailMergeDataField ...

Действия «Найти / Заменить» выполняются в своей собственной процедуре ReplaceTextWithMergeField, в которую передаются имя поля источника данных (как его видит Word!) И целевой диапазон для поиска.

Обратите внимание, как пары угловых скобок добавляются к имени поля данных в этой процедуре.

Действия поиска / замены являются стандартными, переустановка объекта Range для продолжения поиска имени поля данных немного отличается, потому что необходимо получить позицию вне поля слияния - после вставки поля Range находится внутри кода поля. Если этого не сделать, Find может оказаться в том же поле «бесконечно». (Примечание: не в этом случае с двойными угловыми скобками. Но если бы кто-то использовал код без них, тогда возникла бы проблема.)

РЕДАКТИРОВАТЬ: Чтобы найти и заменить в Shape объекты, эти объекты должны быть зациклены отдельно Все, что отформатировано с переносом текста, находится в другом слое документа и не является частью Document.Content. Я адаптировал процедуру поиска в третьей процедуре для поиска по документу ShapeRange, особенно для проверки текстовых полей.

    private void btnDataToMergeFields_Click(object sender, EventArgs e)
    {
        getWordInstance();
        if (wdApp != null)
        {
            if (wdApp.Documents.Count > 0)
            {
            Word.Document doc = wdApp.ActiveDocument;
            Word.Range rng = doc.Content;
            Word.ShapeRange rngShapes = rng.ShapeRange;

            if (doc.MailMerge.MainDocumentType != Word.WdMailMergeMainDocType.wdNotAMergeDocument)
                foreach (Word.MailMergeDataField mmDataField in doc.MailMerge.DataSource.DataFields)
                {
                  System.Diagnostics.Debug.Print(ReplaceTextWithMergeField(mmDataField.Name, ref rng).ToString() 
                      + " merge fields inserted for " + mmDataField.Name);
                  rng = doc.Content;
                  System.Diagnostics.Debug.Print(ReplaceTextWithMergeFieldInShapes(mmDataField.Name, ref rngShapes)
                      + " mergefields inserted for " + mmDataField.Name);

                }
            }
        }
    }

    //returns the number of times the merge field was inserted
    public int ReplaceTextWithMergeField(string sFieldName, ref Word.Range oRng)
    {
        int iFieldCounter = 0;
        Word.Field fldMerge;
        bool bFound;

        oRng.Find.ClearFormatting();
        oRng.Find.Forward = true;
        oRng.Find.Wrap = Word.WdFindWrap.wdFindStop;
        oRng.Find.Format = false;
        oRng.Find.MatchCase = false;
        oRng.Find.MatchWholeWord = false;
        oRng.Find.MatchWildcards = false;
        oRng.Find.MatchSoundsLike = false;
        oRng.Find.MatchAllWordForms = false;
        oRng.Find.Text = "<<" + sFieldName + ">>";
        bFound = oRng.Find.Execute();
        while (bFound)
        {
            iFieldCounter = iFieldCounter + 1;
            fldMerge = oRng.Fields.Add(oRng, Word.WdFieldType.wdFieldMergeField, sFieldName, false);
            oRng = fldMerge.Result;
            oRng.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
            oRng.MoveStart(Word.WdUnits.wdCharacter, 2);
            oRng.End = oRng.Document.Content.End;
            oRng.Find.Text = "<<" + sFieldName + ">>";
            bFound = oRng.Find.Execute();
        }
        return iFieldCounter;
    }

    public int ReplaceTextWithMergeFieldInShapes(string sFieldName,
                               ref Word.ShapeRange oRng)
    {
        int iFieldCounter = 0;
        Word.Field fldMerge;
        bool bFound;

        foreach (Word.Shape shp in oRng)
        {
            if (shp.Type == Office.MsoShapeType.msoTextBox)
            {
                Word.Range rngText = shp.TextFrame.TextRange;
                rngText.Find.ClearFormatting();
                rngText.Find.Forward = true;
                rngText.Find.Wrap = Word.WdFindWrap.wdFindStop;
                rngText.Find.Format = false;
                rngText.Find.MatchCase = false;
                rngText.Find.MatchWholeWord = false;
                rngText.Find.MatchWildcards = false;
                rngText.Find.MatchSoundsLike = false;
                rngText.Find.MatchAllWordForms = false;
                rngText.Find.Text = "<<" + sFieldName + ">>";
                bFound = rngText.Find.Execute();
                while (bFound)
                {
                    iFieldCounter = iFieldCounter + 1;
                    fldMerge = rngText.Fields.Add(rngText, Word.WdFieldType.wdFieldMergeField, sFieldName, false);
                    rngText = fldMerge.Result;
                    rngText.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
                    rngText.MoveStart(Word.WdUnits.wdCharacter, 2);
                    rngText.End = shp.TextFrame.TextRange.End;
                    rngText.Find.Text = sFieldName;
                    bFound = rngText.Find.Execute();
                }
            }
        }
        return iFieldCounter;
    }
0 голосов
/ 14 мая 2018

Существует несколько подходов в зависимости от ваших более широких требований. Если вы будете запускать инструмент по мере необходимости для простых / небольших задач на вашем компьютере с Windows, тогда, вероятно, лучше использовать VBA / макроэкономический подход, поскольку у вас уже есть все, что вам нужно.

Другой подход требует большего кодирования и понимания DOCX, но вы могли бы потенциально масштабировать его и запускать на машинах без библиотек MS Office. Поскольку DocX открыт и основан на тексте, вы можете разархивировать его, обработать содержимое XML и повторно сжать. Есть некоторые ошибки, потому что XML не тривиален. Если вы это делаете, то использование Word Merge Fields лучше (для программиста), чем простой текст, так как поиск полей проще. Обычный текст лучше подходит для человека, работающего с документом / шаблоном, поскольку им не нужно иметь дело с полями слияния, но недостатком является то, что обработка XML может стать намного более сложной. Текст в шаблоне <<Salutation>> может быть нелегко найти в XML - его можно разбить на части.

Другое решение - использовать что-то вроде Docmosis (коммерческий продукт - обратите внимание, я работаю на Docmosis). Плюсы в том, что Docmosis может выполнять замену и выполнять более сложные требования (условные и циклические структуры, например, преобразование PDF). Недостатком является то, что вы должны изучить API и установить программное обеспечение (или обратиться к облаку), а также перевести ваши данные в формат для передачи движку.

Надеюсь, это поможет.

...