Інтернет Windows Android

Генерація шаблону документа з даних користувача. Програмна генерація документів-форм у Word

У попередніх статтях циклу "Автоматизація заповнення документів" я розповів про те, як сформувати інтерфейс програми, організувати перевірку введених даних і отримати число прописом без використання коду VBA. У цій, заключній статті мова піде про чаклунство - перенесення всіх необхідних значень із робочої книги Excel до документа Word. Давайте я покажу Вам те, що має вийти в результаті:

Опис механізму

Для початку загалом опишу, яким саме чином відбуватиметься перенесення даних у документ Word. Перш за все, нам знадобиться шаблон документа Word, що містить всю розмітку, таблиці та ту частину тексту, яка залишатиметься незмінною. У цьому шаблоні необхідно визначити місця, в які будуть підставлені значення з робочої книги Excel - найзручніше це зробити за допомогою закладок. Після цього необхідно впорядкувати дані Excel таким чином, щоб забезпечити відповідність шаблону Word, та й в останню чергу - написати саму процедуру перенесення на VBA.

Отже, все по порядку.

Створення шаблону документа Word

Тут все гранично просто - створюємо звичайний документ, набираємо та форматуємо текст, загалом, домагаємось того, щоб отримати необхідну форму. У тих місцях, куди необхідно буде підставити значення з Excel, потрібно створити закладки. Це робиться так:

Таким чином, потрібно буде створити всі закладки, тобто відзначити всі місця, куди будуть вставлені дані з Excel. Файл, що вийшов, потрібно зберегти як "Шаблон MS Word" за допомогою пункту меню "Файл" -> "Зберегти як...".

Підготовка даних Excel

Я вирішив для зручності помістити всі дані, які потрібно перенести в документ Word, на окремому робочому аркуші під назвою Bookmarks - закладки. На цьому аркуші два стовпці: у першому містяться назви закладок (точно так, як вони названі в документі Word), а у другому - відповідні значення, що підлягають перенесенню.

Частина цих значень отримана безпосередньо з аркуша введення даних, а частина - з допоміжних таблиць, розміщених на аркуші Support. У цій статті я не розбиратиму формули, які розраховують потрібні значення, якщо щось буде незрозуміло - ставте питання в коментарях.

На цьому етапі важливо правильно вказати всі назви закладок – від цього залежить правильність перенесення даних.

Процедура перенесення

А ось це – найцікавіше. Існує два варіанти виконання коду перенесення даних:

  • Код виконується в робочій книзі Excel, дані передаються в Word за одним значенням за раз і відразу розміщуються в документі.
  • Код виконується в окремому документі Word, всі дані передаються із Excel одним пакетом.

З точки зору швидкості виконання, особливо при великій кількості закладок, другий варіант виглядає набагато привабливіше, проте потребує складніших дій. Саме його я й використав.

Ось, що потрібно зробити:

  • Створити шаблон документа Word за допомогою макросів.Цей шаблон містить код, що виконується на VBA.
  • У створений шаблон необхідно розмістити програму, написану на VBA.Для цього необхідно при редагуванні шаблону натиснути комбінацію клавіш Alt+F11 і ввести у вікні редактора Visual Basic код програми.
  • У робочій книзі Excel написати код, що викликає процедуру заповнення із щойно створеного шаблону Word.

Текст процедури я наводити в статті не буду - його можна легко переглянути у файлі FillDocument.dotm, розташованому в папці Template в архіві з прикладом.

Як скористатися всім цим для вирішення саме Вашого завдання?

Розумію, що на словах це все виглядає дуже просто, але що виходить насправді? Я пропоную Вам просто користуватися вже готовим варіантом. Завантажте архів з прикладом, у робочій книзі Excel натисніть комбінацію клавіш Alt+F11, щоб відкрити редактор Visual Basic та прочитайте всі мої коментарі до програми. Для того, щоб змінити програму під свої потреби Вам знадобиться лише змінити значення декількох констант, вони винесені на початок програми. Весь текст програми Ви можете скопіювати у свій проект.

Структура архіву

В архіві, що додається до цієї статті, міститься кілька файлів.

Основний файл – робоча книга Excel з назвою "Створення підтверджень". У цій робочій книзі 4 робочі листи, з яких відображаються тільки два: "Input" - лист введення даних і "Database" - архів всіх введених документів.

У папці Templates є шаблони документів Word. Один з них – шаблон, що містить програму заповнення закладок, а другий – форма для заповнення. Ви можете використовувати без змін шаблон із програмою, але форму для заповнення, природно, доведеться переробити відповідно до Ваших потреб.

Як переробити приклад "під себе"?

  1. Підготувати шаблон документа Word, який потрібно заповнити. Створити у ньому всі необхідні закладки та зберегти як "шаблон MS Word".
  2. Скопіювати в папку з підготовленим шаблоном файл FillDocument.dotm з архіву до цієї статті. Цей файл відповідає за заповнення закладок шаблону, і в ньому нічого не потрібно змінювати.
  3. Підготувати робочу книгу Excel для введення даних. Вам вирішувати, чи вона матиме будь-який "просунутий" інтерфейс користувача і здійснювати різні хитрі розрахунки. Головне, щоб у ній містився робочий лист із таблицею відповідності імені закладки у шаблоні Word та значення, яке потрібно підставити.
  4. Вставити в підготовлену книгу код програми на VBA з файла-прикладу. Замінити всі константи відповідно до Вашого проекту.
  5. Протестувати правильність роботи.
  6. Активно користуватись!

Продовжуємо розпочату раніше тему роботи з формами в Word. У попередніх статтях дивилися на форми лише з погляду “просунутого користувача”, тобто. ми робили документи, зручні для ручного заповнення. Сьогодні ж я хочу запропонувати розширити це завдання та спробувати використати механізм Content controls для генерації документів.

Перш, ніж ми приступимо до нашого безпосереднього завдання, хочу сказати пару слів з приводу того, як зберігаються в документах Word дані для сontent controls (то як вони прив'язуються до вмісту документа я свідомо поки опущу, але сподіваюся повернутися до цього якось у наступних статтях).

Закономірне питання – а що таке itemProps1.xmlта аналогічні компоненти? У цих компонентах зберігаються описи джерел даних. Швидше за все, за задумом розробників крім вбудованих у документ XML-ек, передбачалося використовувати й інші, але поки що реалізований тільки цей спосіб.

Чим корисні нам itemPropsX.xml? Тим, що в них перераховані xml-схеми (їх targetNamespace), які використовуються в батьківському itemX.xml. Це означає, що якщо ми підключили в документ не одну custom xml, то щоб знайти потрібну, нам потрібно пробігтися по itemPropsX.xmlкомпонентам і знайти потрібну схему, а отже, і потрібний itemX.xml.

Тепер ще один момент. Ми не будемо вручну аналізувати зв'язки між компонентами та шукати потрібні, використовуючи лише базовий Packaging API! Натомість ми скористаємося Open XML SDK (його збірки доступні через NuGet). Звичайно, раніше ми не словом не говорили про цей API, але для нашого завдання від нього вимагається мінімум і весь код буде достатньо прозорим.

Що ж, основне введення зроблено, можна приступати наприклад.

За традицією, що склалася, візьмемо все той же “Звіт про нараду”, який ми малювали у статті . Нагадаю, що так виглядав шаблон документа:

А ось так, XML до якого прив'язувалися поля документа

< meetingNotes xmlns ="urn:MeetingNotes" subject ="" date ="" secretary ="" > < participants > < participant name ="" /> < decisions > < decision problem ="" solution ="" responsible ="" controlDate ="" />

Крок 1. Створення моделі даних

Власне, наше завдання не просто згенерувати документ, а створити (хоча б у чорновому варіанті) зручний інструмент для використання як розробником, так і користувачем.

Тому модель ми оголосимо як структури С#-класов:

Public class MeetingNotes ( public MeetingNotes() ( Participants = new List (); Decisions = new List (); ) public string Subject ( get; set; ) public DateTime Date ( get; set; ) public string Secretary ( get; set; ) public List Participants ( get; set; ) Public List Decisions ( get; set; ) ) public class Decision ( public string Problem ( get; set; ) public string Solution ( get; set; ) public string Responsible ( get; set; ) public DateTime ControlDate ( get; set; ) ) public class Participant (public string Name (get; set;))

За великим рахунком, нічого особливого, хіба що додані атрибути для керування XML-серіалізацією (т.к. імена в моделі та необхідної XML трохи різняться).

Крок 2. Серіалізація наведеної вище моделі у XML

Завдання, у принципі, тривіальне. Що називається "беремо наш улюблений XmlSerializer і вперед", якби не одне але

На жаль, у поточній версії Office, очевидно, є баг, який полягає в наступному: якщо в custom xml передоголошенням основного namespace (того, з якого Word повинен брати елементи для відображення), оголосити ще який-небудь, то Content controls, що повторюються, починають відображатися не вірно (показується тільки стільки елементів, скільки було в самому шаблоні - тобто. repeating section не працює ).

Тобто. ось такий xml працює:

< test xmlns ="urn:Test" attr1 ="1" attr2 ="2" > < repeatedTag attr ="1" /> < repeatedTag attr ="2" /> < repeatedTag attr ="3" />

і ось такий теж:

< test xmlns ="urn:Test" attr1 ="1" attr2 ="2" xmlns:t ="urn:TTT" > < repeatedTag attr ="1" /> < repeatedTag attr ="2" /> < repeatedTag attr ="3" />

а ось такий вже немає:

< test xmlns:t ="urn:TTT" xmlns ="urn:Test" attr1 ="1" attr2 ="2" > < repeatedTag attr ="1" /> < repeatedTag attr ="2" /> < repeatedTag attr ="3" />

я намагався відправити баг на підтримку Microsoft на Connect , але в мене чомусь закритий доступ для відправлення багів по Office. А обговорення на форумі MSDN також не допомогло.

Загалом, необхідний обхідний маневр. Якби ми формували XML руками, проблем не виникло б – ми зробили б усе самі. Однак у цьому випадку дуже хочеться використовувати стандартний XmlSerializer, який за замовчуванням додає кілька своїх namespace у вихідний XML, навіть якщо ці namespace не використовуються.

Ми зробимо повне придушення виведення власних namespace у XmlSerializer. Правда, цей підхід спрацює, тільки якщо вони йому і справді будуть не потрібні (інакше вони все одно будуть додані і саме ДО нашого).

Власне, весь код (за умови, що змінна meetingNotesмістить раніше заповнений об'єкт типу MeetingNotes):

var serializer = новий XmlSerializer(typeof (MeetingNotes));
var serializedDataStream = новий MemoryStream();

var namespaces = New XmlSerializerNamespaces();
namespaces.Add(“”, “”);

serializer.Serialize(serializedDataStream, meetingNotes, namespaces);
serializedDataStream.Seek(0, SeekOrigin.Begin);

Крок 3. Заносимо отриману XML Word-документ.

Тут ми чинимо так:

  • копіюємо шаблон і відкриваємо копію
  • знаходимо в ній потрібний custom xml (шукаємо по namespace “urn:MeetingNotes”)
  • замінюємо вміст компонента, на нашу XML

File.Copy(templateName, resultDocumentName, true); using (var document = WordprocessingDocument.Open(resultDocumentName, true )) ( var xmlpart = document.MainDocumentPart.CustomXmlParts .Single(xmlPart => xmlPart.CustomXmlPropertiesPart.DataStoreItem.SchemaReferences.OfType () .Any(sr => sr.Uri.Value == "(!LANG:urn:MeetingNotes"!}

Всі ми маємо справу з текстами, так чи інакше. Іноді виникає потреба згенерувати велику чи не дуже велику кількість тексту для будь-яких завдань, наприклад, погратися з форматуванням, а тексту під рукою немає, самому писати ліньки. Що робити? Відповідь проста: скористатися вбудованим у Word генератором випадкових текстів!

У редакторі Microsoft Word можна генерувати текст досить швидко та легко за допомогою спеціальних команд. Як піддослідний кролик використовуватиму Word 2007. Ці команди повинні працювати у всіх версіях Word. Розповім про три методи генерації тексту.

Метод 1. Використання rand()

Функція rand() вставляє локалізований зразок тексту, 3 абзаци по 3 речення. Відкрийте ваш Word, поставте курсор на те місце, де скоро з'явиться купа тексту і введіть команду:

та натисніть Enter. Сама функція rand зникне і замість неї з'явиться 3 абзаци тексту:

Але це ще не все. Якщо вам потрібно багато тексту, можна використовувати функцію rand з додатковими аргументами, ось у такому вигляді:

=rand(x,y)

де « x» означає кількість абзаців, а « y» — кількість пропозицій у кожному абзаці. Наприклад, =rand(20,5)вставить 20 абзаців із п'ятьма фразами в кожному. А =rand(7)вставить 7 абзаців по 3 речення на кожен.

Метод 2. Використання lorem()

Щоб вставити старий добрий Lorem Ipsum як зразок застосовуємо функцію lorem(). Введіть наступну команду та натисніть Enter:

І отримаємо ось такий всевдо-латинський текст

Функція lorem() також охоче приймає додаткові аргументи, як і rand(), як кількість абзаців і речень. Без аргументів функція вставляє за замовчуванням 3 абзаци з трьома пропозиціями у кожному.

Метод 3. Функція rand.old()

Використання аналогічно попереднім командам:

=rand.old()

та натиснути Enter.

Функція rand.old() залишена для сумісності зі старим офісом до 2003 включно. Спосіб застосування такий самий, як і в попередніх двох, тільки текст складатиметься з однакових фраз «З'їж ще цих м'яких французьких булок, та випий чаю». Цю фразу знає кожен, кому іноді доводилося працювати зі шрифтами.

Можна передавати аргументи, як і перших двох методах.

Ось і все, текстів нагенерили, тепер можна з'їсти ще цих м'яких французьких булок та випити чаю:)

Чи вдалося ви вставити текст за допомогою вищезгаданих функцій?