Шаблонизатор экселя для Go

В процессе работы над платформой Blank, возникла задача генерации документов. Так как платформа предполагает очень широкое применение, очень не хотелось формировать документы полностью программно. Нужно дать возможность интеграторам и администраторам системы удобно создавать шаблоны, на основе которых, в дальнейшем, будут формироваться различные документы.

Сервер написан на Go, поэтому первым делом я принялся изучать что уже придумано умными людьми для решения подобных задач. Оказалось, что совсем не много. Обсуждения, в основном, скатываются в область — есть решения на Яве, используйте их. Неее, не для того мы на Go пишем, чтобы за собой Яву тянуть.

Также, наш сервер поддерживает пользовательские скрипты на Javascript, но полноценных решений тоже не нашлось.

Решено было сделать все самостоятельно. Blank вовсю использует Handlebars, поэтому захотелось использовать похожее поведение для формирования документов. Первым этапом пошли электронные таблицы, то, что мы привыкли видеть в Excel. Родился пакет go-xlsx-templater, которые позволяет разметить документ Excel (.xlsx) тэгами в «усах» и получить, в итоге конечный отчет с данными.

На данный момент, библиотека имеет 4 метода: ReadTemplate(), Render(), Save(), Write(). Рассмотрим небольшой пример использования.

Создаем отчет

Первым делом, нужно создать шаблон документа. У нас есть заголовок с приветствием к пользователю, а так же табличка со списком предметов, находящихся во владении пользователем. Как видим, синтаксис определения снипетов совпадает с Handlebars или Mustache. Важно помнить, в данном случае, что при указании снипета с точкой внутри, как в примере {{items.name}} — это будет означать либо брать свойство из вложенного объекта в переданном контексте, либо из соответствующего элемента в массиве, при этом будет создано нужное количество строк, чтобы заполнить всеми элементами массива, как в нашем случае.

Передаем мы вот что:

	map[string]interface{}{
		"name":           "Github User",
		"nameHeader":     "Item name",
		"quantityHeader": "Quantity",
		"items": []map[string]interface{}{
			{
				"name":     "Pen",
				"quantity": 2,
			},
			{
				"name":     "Pencil",
				"quantity": 1,
			},
			{
				"name":     "Condom",
				"quantity": 12,
			},
			{
				"name":     "Beer",
				"quantity": 24,
			},
		},
	}

После обработки получаем долгожданный документ:

Файл мы можем либо сохранить на диск, либо сразу отдать в ответ на http запрос, благо, библиотека поддерживает интерфейс io.Writer.

Пакет только что создан, еще толком не протестирован, но зато уже его можно как-то использовать в работе. В дальнейшем буду его развивать и улучшать. (Дополнение от 13 июля 2016 года: пакет с марта месяца используется для генерации различных отчетов в одном из подразделений Министерства транспорта РФ и показывает себя только с лучшей стороны).

Полный код демо-приложения выглядит так:

package main

import (
	"github.com/ivahaev/go-xlsx-templater"
)

func main() {
	doc := xlst.New()
	doc.ReadTemplate("./template.xlsx")
	ctx := map[string]interface{}{
		"name":           "Github User",
		"nameHeader":     "Item name",
		"quantityHeader": "Quantity",
		"items": []map[string]interface{}{
			{
				"name":     "Pen",
				"quantity": 2,
			},
			{
				"name":     "Pencil",
				"quantity": 1,
			},
			{
				"name":     "Condom",
				"quantity": 12,
			},
			{
				"name":     "Beer",
				"quantity": 24,
			},
		},
	}
	doc.Render(ctx)
	doc.Save("./report.xlsx")
}

Обработка ошибок здесь не показана, но в реальном приложении, естественно, стоит их учитывать.

Буду рад любым откликам и предложениям по развитию пакета!