Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!

20.01.2023

Як я колись шаблонізував документи Word

Згадали на роботі мову шаблонів Handlebars. Я її дуже люблю, як просту мову для шаблонів, що редагуються користувачами. Хоч ця мова за мірками інтернету стародавня — ще з 2010 року — вона залишається актуальною. Але спогади про Handlebars нагадали мені іншу цікаву історію, як колись довелось генерувати шаблоном документи Microsoft Word.

Задача була доволі проста за змістом. Треба було скласти звіт за зразком, але заповнити даними користувача. Таке зазвичай роблять з HTML, а потім, можливо, перетворюють на PDF, але тут вимога була отримати звіт у форматі DOCX. Було це років десять дому, тож може вже зʼявились рішення простіше. А на той час гарного способу зробити DOCX з HTML або PDF я не знайшов. Часто-густо якщо такий конвертор і знаходиться, то він псує форматування та підходить тільки для внутрішнього використання.

Але ж корисно знати, що формат документів DOCX являє собою XML-документ, запакований в архів ZIP. Це вже обіцяє хоч якусь можливість автоматичного перетворення. Та дійсно, перша спроба розвʼязку була така: взяли зразок та спробували зробити з нього шаблон за допомогою ERB або ще чогось. Але документ DOCX містить набагато більше, ніж ми бачимо на екрані, та прочитати та зрозуміти його вихідний код — це зовсім не те що редагувати звичні шаблони вебсайтів. Тож “простий” шаблон видався незграбним та складним у редагуванні — бо кожна зміна форматування зразка практично тягнула за собою створення шаблону наново.

Тоді прийшла інша ідея шаблонування. Якщо зразок документа відкрити у Ворді, та залишити в ньому текстовий маркер, наприклад: {{NAME}}, а потім цей документ відкрити вже у Ruby, то знайти цей маркер за допомогою Nokogiri буде просто. Та не тільки знайти, а й замінити на інший текст. При цьому заміна отримає форматування, що було прикладене до маркера. Тож наш зразок став шаблоном — зберігаючи можливість його відредагувати. Чудово!

На заміні маркерів робота не закінчилась. Вдалося навіть впровадити такі неодмінні функції шаблонування, як умовні блоки та блоки-цикли. Для цього спрацювали ті ж самі маркери. Але тепер ми знаходили пару маркерів, забирали XML-фрагмент, що знаходиться між ними, та опрацьовували. Єдиний нюанс, що маркери мали знаходитись на одному рівні у дереві XML, але це нескладно було влаштувати вручну. Головне, що при виявленні проблем було достатньо видалити маркери з документа та спробувати знову.

В тестуванні це працювало як потрібно, а у продакшн хитре рішення так і не потрапило.