PHPStamp — честная генерация DOCX документов из шаблона

Это еще одна попытка реализовать стабильный, полноценный шаблонизатор офисных документов, основанных на XML, пользуясь стандартными для PHP средствами DOMDocument и XSL.

Задача состояла именно в генерации шаблона для многократного использования, который не придется править вручную или прибегать к сторонним программам для его доработки.

Найти библиотеку можно здесь: github.com/shadz3rg/PHPStamp

Принцип работы


Несмотря на все прелести визуальных редакторов, на выходе всегда получается далеко не самый оптимальный код документа, и MS Word — не исключение. Вот так просто добавленные в документ Тэги заменить на XSL логику не получится, даже не смотря на относительно простую структуру DOCX документа.

Основную проблему представляют разбитые на отрывки (они же «run», представлены нодами <w:r/>) параграфы, содержимое Тэгов разбивается на несколько нод и в таком виде их обработать не получится.

Для начала попробуем упростить разметку.

1. Удалим свойства языка у отрывков. Что логично, при замене Тэга может быть вставлено значение на любом языке, к тому же знаки пунктуации не имеют принадлежности к языку, что доставляет дополнительные проблемы при поиске Тэгов.
2. Удалим пустые ноды свойств отрывков, чисто технический момент.
3. Объединим рядом стоящие отрывки, используя deepEqual сравнение (которое в DOMDocument до сих пор «Not implemented») нод свойств.

Если все прошло по плану, библиотеке остается лишь добавить подходящую XSL логику. Предусмотрена возможность — некоторая расширяемость с опциями. Так, например, на данный момент реализованы табличные строки и списки.
Полученный шаблон кэшируется в файловой системе, поэтому последующие его вызовы будут максимально быстрыми (настолько, насколько способен XSL).

Предусмотрена поддержка разных форматов. В планах было добавить поддержку формата ODT, но ввиду отличной поддержки DOCX в LibreOffice особой необходимости нет. Возможно, хорошей идеей будет генерация XLSX, должно получится довольно быстро в сравнении с PHPExcel.

Зависимости и установка


Установить библиотеку вы можете через Composer, на сервере понадобится PHP 5.3 с модулями Zip, DOM и XSL.

{
    "minimum-stability": "dev",
    "require": {
        "shadz3rg/php-stamp": "dev-master"
    }
}


Пример использования


Для примера используем шаблон:



<?php
	require 'vendor/autoload.php';

	use PHPStamp\Templator;
	use PHPStamp\Document\WordDocument;

	$cachePath = 'path/to/writable/directory/';
	$templator = new Templator($cachePath); // опционально можно задать свой формат скобочек
	// Для того чтобы каждый раз шаблон генерировался заново: 
	// $templator->debug = true;

	$documentPath = 'path/to/document.docx';
	$document = new WordDocument($documentPath);

	$values = array(
		'library' => 'PHPStamp 0.1',
		'simpleValue' => 'I am simple value',
		'nested' => array(
			'firstValue' => 'First child value',
			'secondValue' => 'Second child value'
		),
		'header' => 'test of a table row',
		'students' => array(
			array('id' => 1, 'name' => 'Student 1', 'mark' => '10'),
			array('id' => 2, 'name' => 'Student 2', 'mark' => '4'),
			array('id' => 3, 'name' => 'Student 3', 'mark' => '7')
		),
		'maxMark' => 10,
		'todo' => array(
			'TODO 1',
			'TODO 2',
			'TODO 3'
		)
	);
	$result = $templator->render($document, $values);
	$result->download();


На выходе получаем документ с нужными нам данными:

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 15

    0
    Есть интерес к генерации XLSX, на сколько у вас проработана работа с графиками? Сейчас некоторые моменты нельзя сделать PHPExcel.
      0
      XLSX только в планах.
        0
        Ок, последим за развитием.
          0
          Несколько месяцев назад передо мной стояла задача формирования реестров операций в формате xlsx. На первой итерации была использована библиотека PHPExcel, но после проверки полученного решения на прогнозируемых объёмах (120 тыс. операций) от использования PHPExcel пришлось отказаться.

          Библиотеку PHPExcel можно использовать лишь для небольших шаблонов. При значительном увеличении количества строк начинает проседать производительность (время заполнения шаблона начинает измеряться минутами) и памяти начинает резко не хватать (уже на 10 тыс. операций мы получили превышение 128 Мб).

          Согласно требованиям к разрабатываемому ПО в реестре могло быть около 100-200 тыс. операций, поэтому пришлось реализовывать свой шаблонизатор под конкретные задачи с минимальным потреблением памяти. Полученное решение тестировани на 1 млн. операций. Потребление памяти не зависит от количества строк (строки сразу пишутся в файл), производительность существенно выше (если правильно помню, тофайл на 1 млн. строк формировался за пару минут).

          Поэтому если будете реализовывать свой генератор xlsx-файлов и хотите избежать проблем с памятью и производительностью, то лучше отказаться от хранения всех данных в памяти при заполнении шаблона и, как следствие, не использовать XSLT.
            0
            А поделитесь-ка пожалуйста, если это не сверх секретно)
        0
        А есть отчет по скорости?
        Делал экспорт прайслиста с помощью PHPword через шаблоны — документ из 50 строк таблицы создавался 2 минуты!
        O_o

        И можно ли вставлять в шаблон картинки?
          0
          Уверен что сильно быстрее, о производительности даже не задумывался так как после генерации шаблона на XSL трудно повлиять.
          Думаю возможность вставлять картинки будет в ближайшем времени, для полной работы только ее и не хватает.
          0
          Cпасибо, заstarил на github.
            0
            Основную проблему представляют разбитые на отрывки (они же «run», представлены нодами <w:r/>) параграфы, содержимое Тэгов разбивается на несколько нод и в таком виде их обработать не получится.


            и все-таки вариант есть :) — через RTF формат. Сам делал шаблонизатор через WORD. Вот пример шаблона для вывода 2-х таблиц:
            image

            Если интересно — пишите, с удовольствием поделюсь идеей…

              0
              Вспомнил свою древнейшую статью, за которую когда-то получил инвайт.
              Правда из-за ее примитивности и устарения информации в ней, давно скрыл в черновики. (восстановил, если кому будет интересно о чем речь)
              Спасибо за возраждение идеи!
                0
                Интересный подход (в своём велосипеде «переменные» обрабатывал сразу после нахождения), но, ИМХО, для практического использования не хватает условий (при их реализации начинается самое интересное :))
                  0
                  gist.github.com/ya-est/e741bec6db04b22ddddd

                  В своем время написал свой «велосипед» для генерации DOCx в 100 строчек (вместе с комментариями и возможностью расширения для «особых нужд»). Проблем никаких не было.

                  Принцип работы:
                  Открыть docx как архив, заменить текст регуляркой в файле word/document.xml, обновить файл и создать новый архив.
                    0
                    Еще есть OpenTBS
                      0
                      github.com/PHPOffice/PHPWord не смотрели?
                        0
                        Doctrine\Common\Lexer\AbstractLexer
                        Хотел потестить, а оказалось тут завязка под доктрин идет.
                        Не совсем то что ожидал от библиотеки.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое