Предыстория
Всем привет! Меня зовут Женя и я программист. Ничего особенного. Пока что.
Сегодня я хотел бы поделиться историей с хорошим концом, которая убедила меня в том, что даже если ты не относишь себя к программистам выше среднего и решаешь тривиальные задачи, программирование как процесс может всё равно быть очень увлекательным!
Перед мной стояла одна из самых типичных задач: вывести данные в какой-то текстовый файл. Формат файла такой, чтобы открылся на любом настольном среднестатистическом устройстве. Я был уверен в простоте решения этой задачи. Но в эту неделю судьба решила преподать мне урок…
История
Всё началось с выбора библиотеки для облегчения жизни и выбора формата. Формат был выбран docx а библиотека OenTBS. Вроде бы всё в ней было как надо — и формат файла тот и использовать шаблон можно. Но как показали 3 дня работы, эта штука если и может работать с вложенными массивами, то таким не очевидным образом, что, возможно, нужно вступить в какую-то секту, что бы постичь сие. Я решил идти по пути наименьшего сопротивления и просто поделился с монитором своими мыслями по поводу этой библиотеки и начал искать другую.
Далее был простой инструмент под названием odtPHP. Чей сайт, похоже, не работает до сих пор. Как Вы уже догадались вместе с библиотекой пришлось сменить и формат — им стал odt. Если очень захотеть можно даже порадоваться — открытый формат и всё такое.
Вот тут и началось самое веселое. Документ генерируется из шаблона. Если сделать шаблон в LibreOffice (а именно он был у меня первым под рукой), то в Word`е он будет открываться только после вопроса о восстановлении. А если создать шаблон в Word`е? Тогда без восстановления. Но после минимальных правок в шаблоне odtPHP выдавал ошибку, мол в шаблоне не найдена переменная. Неистовый воплю и тыканье пальцем в название переменной в шаблоне делу не помогли. Странно. То есть получалось, что нужная переменная как бы прописана в шаблоне, но odtPHP не может найти эту переменную через регулярные выражение.
Начали закрадываться подозрения, что пробел/тире/любой-другой-символ в Word`e в самом исходнике может обозначаться как-то иначе. Так как я знал что odt, как и docx, это по простому архивированные XML я решил углубиться в этот вопрос и для пущей уверенности создал такой же odt-шаблон через Google Drive. После разархивирования odt-файлов от разных «создателей» получилась вот такая картина:
Стало очевидно что формат форматом, но у программ может быть разный на него взгляд. Как несложно догадаться, всё содержимое файла хранится в content.xml. Открываю. Ищу свои переменные. И, о чудо! Я на верном пути! Вот так моя переменная выглядит в Word`е (вариант созданный в Word`e):
А вот так этот фрагмент выглядит в content.xml:
А регулярное выражение было максимально простым:
$reg = '@\[!--\sBEGIN\s' . $string . '\s--\](.*)\[!--.+END\s' . $string . '\s--\]@smU';
Что такое <text:s/> узнать так и не удалось. Можно подумать, что это пробел, но почему он вставился именно тут, а в других местах просто пробел? Не понятно. Предугадать расстановку таких магических пробелов в Word`е не предоставилось возможным. Вот и получилось, что Word где-то вставляет пробел как пробел, а где-то как <text:s/>, что обламывает нахождение переменной по минимальному шаблону.
Вот так тривиальная задача превратилась в увлекательное довольно путешествие по структуре формата odt!
Мораль
Каким бы уровнем знаний вы не обладали и как низко бы не падала оценка собственных навыков, не бойтесь копнуть глубже! Если, конечно, вы не водитель экскаватора и рядом не визит табличка «Копать запрещено».