Примерно полгода назад, к статье Электронные формы в Microsoft Word 2007: простые формы “парой кликов” был добавлен комментарий от Яны Ивановой, в котором было вот такое замечание:
размножить поля с ответами, если их надо вписать несколько, там не получится
На самом деле, вопрос про вставку/извлечение табличных данных в формы Word звучал еще раньше. К сожалению, Word 2007/2010 при использовании механизма Сontent Сontrols (о котором и шла речь в статье) позволяли создавать электронные формы только с заранее заданным, жестким количеством полей.
Да, был еще один механизм, под названием Custom XML, который существовал еще для Office 2003, и даже был включен в ISO стандарт на формат файлов .docx. Но, увы:
- он был сложнее в использовании, чем Сontent Сontrols (как минимум, он работал только с XML Schemas, а не исходным XML)
- Microsoft был вынужден удалить этот механизм из Office под давлением компании i4i
(чуть более подробно и о механизме и о патентном споре можно прочесть тут).
Получается, что ни о таблицах, ни о списках (даже такой, простой с виду вещи, как переменный список подписантов/согласующих) в электронных формах на базе Word речь идти не могла.
Однако, все меняется, и такой востребованный механизм появился-таки в Office 2013. Более того, теперь в Word есть собственный инструмент привязки Content Controls к узлам XML (чтобы потом извлекать/загружать данные в документ), а значит необходимость в сторонних утилитах, таких как Word Content Control Toolkit отпала.
Давайте посмотрим, как работают эти 2 механизма!
Шаг 0. Создание исходного документа
Для начала создадим исходный документ. Пусть это будет шаблон отчета о совещании, а в качестве данных для формы возьмем:
- Одиночные поля: тема совещания, дата, ФИО секретаря
- Список: список участников
- Таблица: таблица принятых решений (столбцы: Вопрос, Принятое решение и Ответственный, Контрольный срок)
Шаг 1. Определение структуры XML для сохранения результата
Особо не будем придумывать и остановимся на следующей структуре:
<?xml version="1.0" encoding="utf-8"?>
<meetingNotes xmlns="urn:MeetingNotes" subject="" date="" secretary="">
<participants>
<participant name=""/>
</participants>
<decisions>
<decision problem="" solution="" responsible="" controlDate=""/>
</decisions>
</meetingNotes>
Тэги <participant> и <decision> могут повторяться многократно. Пространство имен (в примере оно urn:MeetingNotes) желательно указать.
Сохраним полученный XML на диске.
Шаг 2. Подключение созданного XML в шаблон документа
- Переходим на закладку Developer и нажимаем “XML Mapping Pane”
- В открывшейся панели раскроем список доступных XML-частей и выберем пункт (Add new part…)
- В открывшемся диалоге выберем ранее созданный XML-файл
- Снова раскроем список доступных XML-частей и выберем только что добавленную:
Шаг 3. Добавление content controls для одиночных полей на форму
Процедура простого добавления была описана в статье, но мы пойдем немного иным путем – будем создавать контролы, сразу привязанные к узлам схемы.
Посмотрим, как создать такое поле для темы (и связать его с атрибутом subject):
- Ставим курсор на место, где будет располагаться тема (в нашем случае еще предварительно придется удалить слова Тема и поменять стиль с курсива на обычный)
- В панели XML Mapping щелкаем на элемент @subject и в контекстном меню выбираем Insert Content Control\Plain Text
- Выбираем вставленный контрол и щелкаем на “Properties” на закладке Developer
- В открывшемся окне вводим заголовок для контрола
Результат:
Полностью аналогично поступаем с полем “ФИО секретаря“ (его свяжем с атрибутом @secretary). А вот для поля дата будет ряд отличий:
- При вставке контрола вместо Plain Text выберем Date Picker
- В свойствах контрола установим локаль (язык) и формат даты – чтобы выводить дату в привычном нам виде, а также как сохранять дату в XML (только дату):
Полученный промежуточный результат выглядит вот так:
Шаг 4. Создание списка участников
- Приведем список участников к виду “заголовок и один пустой маркер списка” (можно просто удалить все, и создать пустой список) и поставим курсор на первую строчку списка:
- На закладке Developer выбираем вставку элемента Repeating Section:
Получим примерно такой результат
- В панели XML Mapping щелкаем на элемент partisipants, раскрываем на один уровень вниз, выбираем элемент participant и в контекстном меню выбираем Insert Content Control\Map to Selected Content Control
- Не снимая выделения с контрола, задаем его параметры:
- Вновь выделяем контрол, и заменяем содержимое в нем на 1 пробел (звучит как шаманство, но это нужно, чтобы сохранился наш стиль списка)
- Переставляем курсор перед пробелом, переходим на панель XML Mapping, раскрываем дерево от элемента participant вниз до @name, выбираем элемент @name и в контекстном меню выбираем создание Plain Text контрола
- Задаем параметры добавленного контрола
- Снова возвращаемся к параметрам Repeating Section. Тут нужно поставить курсор внутри секции, но за вставленным контролом для имени (контролировать, что мы все правильно сделали можно по появившемуся имени секции Участники):
- Вновь открыть свойства секции и поставить галочку
Последняя манипуляция нужна для того, чтобы пользователь, когда будет редактировать не ткнул случайно мимо нашего контрола для ввода имени. Это не страшно с точки зрения внешнего вида, но печально скажется на извлечении данных.
Ну и примерно так выглядит текущий шаблон:
Шаг 5. Настройка таблицы решений
- Преобразуем таблицу так, чтобы осталась только шапка и 1 пуста строка:
- Выделяем эту пустую строку и вставляем элемент Repeating Section, как на предыдущем шаге и также аналогично:
- Указываем параметры вставленной секции
- Привязываем нашу секцию к элементу decision (он будет виден, если раскрыть decisions)
- Вставляем элементы для каждой ячейки:
- Встаем в первую ячейку в строке
- Раскрываем элемент decision в панели XML Mapping
- Щелкаем на элемент @problem и выбираем в контекстном меню
- Настраиваем элемент
- … повторяем предыдущие шаги для пар:
- Принятое решение – @solution
- Ответственный – @responsible
- Контрольный срок – @controlDate
- Вновь выделяем секцию Решения и как мы делали со списком – запрещаем редактирование.
Наш результат:
Шаг 6. Защищаем форму от изменений и сохраняем как шаблон
Теперь осталось защитить от изменений всю нашу форму (оставляя только возможность заполнения полей). Хоть эта процедура была описана в прошлой статье, пройдусь по ней еще раз:
- Все на той же закладе Developer нажимаем “Restrict Editing”
- На открывшейся панели ставим галку “Allow only this type of editing in the document”, в выпадающем списке выбираем “Filling in forms” и нажимаем кнопку “Yes, Start Enforcing Protection”
- В открывшемся окне вводим какой-нибудь пароль (еще раз напоминаю, что мы защищаемся от случайного изменения, а вовсе не от преднамеренной подделки или порчи):
- Сохраняем документ как шаблон:
Все, наш шаблон готов!!!
Теперь на основе его мы можем создавать сколько угодно реальных отчетов. Вот так выглядит такой документ в процессе редактирования (обратите внимание на значок “+”, с помощью которого мы добавляем новые элементы в списки и таблицы):
Ну и, конечно, резонный вопрос: как получить данные, введенные в форму?
Шаг 7. Получаем данные
- Заполним наш документ… например, во так:
- Сохраним документ, а затем поменяем его расширение на .zip.
- Откроем наш полученный .zip-архив (если у вас Windows 7 и старше, то это не составит проблемы, иначе нужно будет предварительно распаковать архив), перейдем к папке customXml, выберем и откроем файл item1.xml:
- Увидим мы, приблизительно вот такой результат:
<?xml version="1.0" encoding="utf-8"?>
<meetingNotes xmlns="urn:MeetingNotes"
subject="Результаты разработки шаблонов отчетов совещаний"
date="2013-09-21" secretary="Романов М.">
<participants>
<participant name="Романов М."/>
<participant name="Бушмелев С."/>
<participant name="Просалов М." />
</participants>
<decisions>
<decision problem="Как результат?" solution="Устраивает!"
responsible="Романов М." controlDate="2013-09-23T00:00:00"/>
<decision problem="Что дальше?" solution="Внедряем!!!"
responsible="Романов М." controlDate="2013-12-31T00:00:00" />
</decisions>
</meetingNotes>
<?xml version="1.0" encoding="utf-8"?>
<meetingNotes xmlns="urn:MeetingNotes"
subject="Проблемы..."
date="2013-09-21" secretary="Неизвестный Н.">
<participants>
<participant name="Известный, но плохо К."/>
<participant name="Почти-Незаметный В."/>
</participants>
<decisions>
<decision problem="Кто виноват?" solution="Все!"
responsible="Кто-Попался Т." controlDate="2000-01-01"/>
<decision problem="Что делать?" solution="Не знаю!!!"
responsible="Кто-Попался-Повторно Й." controlDate="2999-12-31" />
</decisions>
</meetingNotes>
Обратите внимание, что поменялось в том числе число элементов в списке – все в соответствие с данными в XML!
Конечно, извлечение данных вручную – занятие не для слабонервных! Но тут можно сказать только одно – все же данный инструмент в большей степени рассчитан на разработчиков. Да, создавать формы может любой опытный пользователь, а вот автоматизация их обработки – дело для разработчика.
Для тех, кто все же имеет разработчика под рукой, могу сослаться в качестве примера на статью Электронные формы в Microsoft Word 2007: извлечение и вставка данных.
Ну и для тех, кому не хочется проделывать все шаги статьи, чтобы только убедиться, что автор не наврал (или кто захочет повторить процесс целиком или частично), прикладываю документы, которые создавались в процессе работы:
Pingback: Формы в Word (вопросы и ответы). Часть 1. Форматирование и защита ячеек таблиц | Михаил Романов
Михаил, доброго времени суток.
Спасибо за Вашу статью, очень помогла.
На основе уже подготовленных Вами документов, подскажите, пожалуйста, как можно сделать в защищенной форме добавление, при необходимости, строк таблицы, аналогичных предыдущим? (Word 2010).
Андрей, добрый день.
Увы, вынужден Вас огорчить. Функционал RepeatingSection появился только в Office 2013 и сделать форму с таблицей в более ранних версиях не представляется возможным.
Или я вас не вполне верно понял?
Поняли верно.
Спасибо.
Михаил, добрый день. Вы пишите макросы для Word 2013? Никак не получается скопировать таблицу из Word в Excel…В Word таблица записана визуальна в n-столбцов, но когда ее копируешь в Excel, то она копируется в 1 столбец….Таблицы с большим количеством строк (от 2000) и в ручную форматировать их возможно, но время жалко терять на такую работу. Помочь можете в этом? С уважением, Владимир
Добрый день, Владимир.
Откровенно говоря, я не очень большой специалист в VBA, поэтому если мне нужен наскоро какой-то макрос, я в лучшем случае использую читерский прием – включаю запись макросов.
Поэтому максимум, что я могу вам предложить – вот такое сочетание 2-х записанных наскоро макросов:
Sub Macro2()
Dim Excel As New Excel.Application
Dim WorkBook As Excel.WorkBook
Dim WorkSheet As Excel.WorkSheet
Selection.Tables(1).Select
Selection.Copy
Set WorkBook = Excel.Workbooks.Add
Set WorkSheet = WorkBook.Worksheets(1)
Excel.Visible = True
WorkSheet.Paste
End Sub
Он копируют 1 таблицу в Word (откуда и должен быть вызван) и вставляет на 1 страницу в Excel.
Надеюсь, это подтолкнет ваши дальнейшие изыскания