Не так давно, в нашей программе потребовалось сделать отчет, который представлял из себя некий договор на n-листах в формате doc. Программа пишется на .NET, отчеты делаем на StimulSoft Reports.Net. Сложность была еще и в том, что пользователям программы необходимо было дать возможность править шаблон отчета. В Stimulsoft Reports.NET есть дизайнер шаблона, но, согласитесь, он не очень подходит для рядового пользователя программы.
После нескольких попыток корректно переложить шаблон отчета, было принято решение оставить этот шаблон в word-формате. Как у нас это получилось читайте ниже.
P.S. Чтобы было понятней и наглядней, я создал маленький тестовый проект, который вы можете скачать в конце этого топика.
В нашем примере будем работать со следующей схемой:
Открываем новый документ Microsoft Word (от 2007 и выше, нужна возможность сохранять документ в формате docx). Печатаем некий документ, который мы хотим увидеть на выходе (можно с тестовыми данными).
У меня получился вот такой документ:

Теперь необходимо привязать созданную ранее схему к нашему документу. Для этого необходимо во вкладке «Разработчик» зайти в «Схемы» и добавить нашу созданную схему. В окне выбора псевдонима для схемы напишите название схемы, к примеру test. После чего справа должна открыться вкладка с выбором элементов из схемы.

Если у вас не видна вкладка «Разработчик» инструкция по ее отображению:
Осталось раскидать наши элементы по документу. У меня получилось следующее:

Немного комментариев по расположению элементов. Как вы видите на рисунке, есть 2 типа блоков:
— сиреневые не закрашенные (сложные элементы)
— сиреневые закрашенные (элементы-поля). В этих элементах как раз и будет выводиться текст из xml данных. Иногда Word будет выставлять вам эти поля сиреневыми не закрашенными. Чтобы преобразовать их, необходимо перед элементам поставить любой символ и затем стереть его.
Сохраняем наш файл в формате word document 2007 (с расширением docx).
Теперь запускаем Visual Studio, будем вызывать наш отчет с отправкой в него xml данных. Подсоединяем в проект наш небольшой класс для работы с DocX отчетами и добавляем Reference DocumentFormat.OpenXml (необходимо поставить OpenXMLSDKv2).
Добавим пару кнопок на форму. Первая будет просто открывать файл docx для правки шаблона:
Вторая будет открывать файл docx с нашими xml данными:
Все запускаем, тестируем. Нажимаем кнопку «открыть шаблон», открывается word документ с нашим шаблоном. Вносим изменения, сохраняем. Запускаем «отчет с данными» и любуемся изменениями, сохраненными в шаблоне.
Класс DocxReports не включает в себя ничего сложно, выполняет по сути рекурсивную замену XmlBlock-ов в шаблоне данными из xml.
P.S Конечно у данного подхода есть минусы:
Спасибо за внимание, буду рад выслушать критику, рекомендации. Исходники проекта
После нескольких попыток корректно переложить шаблон отчета, было принято решение оставить этот шаблон в word-формате. Как у нас это получилось читайте ниже.
P.S. Чтобы было понятней и наглядней, я создал маленький тестовый проект, который вы можете скачать в конце этого топика.
Составление XSD-схемы
В нашем примере будем работать со следующей схемой:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="BulletinOfClosedVoting"
targetNamespace="http://test.ru/test.xsd"
elementFormDefault="qualified"
xmlns="http://test.ru/test.xsd"
xmlns:mstns="http://test.ru/test.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="TestDocxReport">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
<xs:element name="PatrName" type="xs:string" />
<xs:element name="Age" type="xs:int" />
<xs:element name="BirthDate" type="xs:date" />
<xs:element name="Books">
<xs:complexType>
<xs:sequence>
<xs:element name="Book" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string" minOccurs="0" />
<xs:element name="Author" type="xs:string" minOccurs="0" />
<xs:element name="ToDate" type="xs:date" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Создание DocX шаблона
Открываем новый документ Microsoft Word (от 2007 и выше, нужна возможность сохранять документ в формате docx). Печатаем некий документ, который мы хотим увидеть на выходе (можно с тестовыми данными).
У меня получился вот такой документ:

Теперь необходимо привязать созданную ранее схему к нашему документу. Для этого необходимо во вкладке «Разработчик» зайти в «Схемы» и добавить нашу созданную схему. В окне выбора псевдонима для схемы напишите название схемы, к примеру test. После чего справа должна открыться вкладка с выбором элементов из схемы.

Если у вас не видна вкладка «Разработчик» инструкция по ее отображению:
Осталось раскидать наши элементы по документу. У меня получилось следующее:

Немного комментариев по расположению элементов. Как вы видите на рисунке, есть 2 типа блоков:
— сиреневые не закрашенные (сложные элементы)
— сиреневые закрашенные (элементы-поля). В этих элементах как раз и будет выводиться текст из xml данных. Иногда Word будет выставлять вам эти поля сиреневыми не закрашенными. Чтобы преобразовать их, необходимо перед элементам поставить любой символ и затем стереть его.
Сохраняем наш файл в формате word document 2007 (с расширением docx).
Запускаем отчет с xml данными
Теперь запускаем Visual Studio, будем вызывать наш отчет с отправкой в него xml данных. Подсоединяем в проект наш небольшой класс для работы с DocX отчетами и добавляем Reference DocumentFormat.OpenXml (необходимо поставить OpenXMLSDKv2).
Добавим пару кнопок на форму. Первая будет просто открывать файл docx для правки шаблона:
DocxReports.ShowTemplate("Reports/TestReport/test.docx");
Вторая будет открывать файл docx с нашими xml данными:
const string xml = @"
Петров
Петр
Петрович
40
30.01.1962
Дело Артамоновых
Горький М.
04.05.2011
Битва железных канцлеров
Пикуль В.
08.05.2011
";
DocxReports.Show("Reports/TestReport/test.docx", xml);
Все запускаем, тестируем. Нажимаем кнопку «открыть шаблон», открывается word документ с нашим шаблоном. Вносим изменения, сохраняем. Запускаем «отчет с данными» и любуемся изменениями, сохраненными в шаблоне.
Логика работы класса
Класс DocxReports не включает в себя ничего сложно, выполняет по сути рекурсивную замену XmlBlock-ов в шаблоне данными из xml.
P.S Конечно у данного подхода есть минусы:
- У пользователя на компьютере обязательно должен стоять Word или OpenOffice, поддерживающий формат docx
- отчет используется только для подстановки данных, т.е произвести какие-либо вычисления в самом отчете не получится, придется подсчитывать в самой программе и отправлять в отчет уже готовое значение
Спасибо за внимание, буду рад выслушать критику, рекомендации. Исходники проекта