Долго думал, в какой форум — решил в профильный. Хотя любители покричать про тупых программистов, пишущих тормозные программы, тусуются в основном в КСВ. Сам я тоже склонен сочувствовать юзерам, не понимающим, почему компьютеры всё мощнее и мощнее, а софт всё тормознее и тормознее. Однако вчера, занимаясь причёсыванием своих PHP+XSLT наработок, почувствовал всю глубину диалектического дуализма ситуации. Дело в том, что формы в админке у меня теперь генерируются в ТРИ прохода XSLT-процессора.
Прежде чем я расскажу, как дошёл до такой жизни, хочу заметить, что убедить меня отказаться от этого решения можно только одним способом: предложив не менее компактную на уровне исходников и не менее удобную для использования альтернативу. Оптимизировать в ущерб компактноти кода я не намерен. Кто заговорит про требования по производительности, первым делом получит предложение переехать с php на java, а вторым — пойти куда подальше. И кстати, я не занимался замерами производительности XSLT, но склонен полагать, что его загрузка и интерпретация сжирает как минимум не меньше времени, чем собственно исполнение. А сами формы, обрабатывающиеся в несколько проходов, составляют лишь малую часть всего кода страницы.
Так вот, откуда три прохода.
Первый (с конца) проход. Если никаких форм на странице нет, он мог бы быть и единственным. На входе XML-дерево, содержащее полный неупорядоченный набор данных, необходимых для генерации HTML-кода страницы. На выходе — HTML. Я выделил жирным тот момент, который радикально расходится со всеми виденными мною примерами использования XSLT. В примерах логическая структура входного дерева заточена под требуемую структуру результата, например:
Ясно, что трансформацию здесь напишет и ребёнок. Но при этом накладываются непомерные требования на код, генерирующий входной XML: фактически, он ставится в зависимость от XSLT-слоя в частности и от дизайна вообще. Поэтому на все эти "good practices" я блогополучно забил, и чаще предпочитаю импортировать и наследовать <template name=""/>, чем <template match=""/> (к счастью, это возможно):
Второй проход. Что меня постоянно напрягало в html-формах, это необходимость вручную прописывать значения по умолчанию в полях <input>. Далее, CSS селекторы невозможно настроить на input/@type, поэтому хотелось бы дублировать атрибут type в class. Также, атрибуты disabled="disabled" и readonly="readonly" раздражают своей громоздкостью и также напрашиваются на дублирование в class (в частности, я подсвечиваю readonly text field как disabled, чтобы народ не путался). И наконец, хотелось бы сделать автоматическую подсветку ошибочных полей, не накладывая ограничений на дизайн/вёрстку. Отсюда возникает следующая трансформация (привожу в несколько схематичном виде):
Здесь CSS-класс w100 — сокращение для {width:100%}. Как видите, трансформация достаточно прямолинейная, по крайней мере для стандартных полей: один элемент на входе, один на выходе. Так
Почему отдельный проход: из неструктурированного входного XML-дерева здесь получается HTML, но с вкраплениями элементов <f:*>, которые должны быть ещё раз оттранслированы. Здесь я поступаю совершенно грубо: поскольку форм у меня полно на самых разных страницах (а частенько формы логина и поиска присутствуют в основном шаблоне), я прогоняю повторно весь контент, вместо того, чтобы оборачивать каждую форму в аналогичную конструкцию:
<x:template match="/">
<x:variable name="x">
<x:copy-of select="/response"/> <!-- обеспечивает доступ к полному входному XML-дереву изнутри вложенной обработки -->
<x:apply-templates select="/" mode="ex"/>
</x:variable>
<x:apply-templates select="ex:node-set($x)/html"/>
</x:template>
<x:template match="/" mode="ex">
<html>...</html>
</x:template/>
Третий (с конца) проход. Выписывать эти <table>, <tr>, <th>, <td> напрягает. Большинство форм имеют такую табличную структуру (а уж админские в моём праве сделать все такими), поэтому нужно бы автоматизировать. Однако для сохранения гибкости для всяких нетривиальных случаев дизайна необходимо оставить вышеописанные примитивы. Отсюда возникает следующая трансформация:
<!-- SOURCE -->
<ft:form name="editpage">
<ft:text th="URI:" name="uri" class="w100" readonly="1"/>
<ft:text th="Title:" required="1" name="title" class="w100"/>
<ft:fckeditor th="Text:" name="text" class="w100"/>
</ft:form>
<!-- RESULT -->
<!-- См. SOURCE с предыдущего прохода. -->
Тупо свести <ft:form> к <x:call-template name="f:form"> не выходит, потому как внутри <f:form> генерируется дополнительный контент: <table>. Отсюда получаем следующее (несколько упрощённо, но "основано на реальных событиях"):
<x:template match="ft:form">
<!-- Здесь я не только генерирую <f:*>, но и сразу же транслирую их в HTML.
Поэтому второй проход переведёт <ft:*> сразу в HTML. -->
<x:variable name="x">
<x:copy-of select="/response"/>
<f:form>
<x:apply-templates select="descendant::ft:hidden" mode="ft:_field"/>
<x:copy-of select="@*"/>
<table>
<x:apply-templates/>
</table>
</f:form>
</x:variable>
<x:apply-templates select="ex:node-set($x)/f:form"/>
</x:template>
<!-- Already processed by <ft:form>, outside generated <table>. -->
<x:template match="ft:hidden"/>
<!-- Any ft:field syntax matches f:field syntax, including element name, attributes and content.
Added special attributes: @th, [@required=1]. -->
<x:template match="ft:*">
<tr>
<f:errclass/>
<th>
<x:value-of select="@th"/>
<x:if test="@required=1">
<f:required/>
</x:if>
</th>
<td><x:apply-templates select="." mode="ft:_field"/></td>
</tr>
</x:template>
<!-- INTERNAL. -->
<x:template match="ft:*" mode="ft:_field">
<x:element name="f:{local-name()}">
<x:copy-of select="@*[name()!='th' and name()!='required']"/>
<x:apply-templates/>
</x:element>
</x:template>
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Дело в том, что формы в админке у меня теперь генерируются в ТРИ прохода XSLT-процессора.
имхо, проще это решение проще пристрелить, чем оптимизировать
ДГ>Оптимизировать в ущерб компактноти кода я не намерен. Кто заговорит про требования по производительности, первым делом получит предложение переехать с php на java, а вторым — пойти куда подальше.
балланс производительность/к-во кода (времени) — спор давний и поклонники С++ и асма давно борятся с шарповщиками, вэбэшниками и делфистами. Потому если заказчику подходит — пусть он остается в счастливом невединии.
If the message above is in English — means I'm wasting my work time and work computer to post here. No hard feelings
Здравствуйте, Niemand, Вы писали:
ДГ>>Дело в том, что формы в админке у меня теперь генерируются в ТРИ прохода XSLT-процессора.
N>имхо, проще это решение проще пристрелить, чем оптимизировать
Гы. На самом деле можно оптимизировать. Тупо продублировать коды f:* в ft:*. Изначально у меня так и было, но я решил пойти по пути математиков: вылил нафиг всю воду из чайника, сведя задачу к уже решённой.
Несколько месяцев назад я обещал кому-то показать работающий крупный сайт с XSLT на стороне клиента. Однако ни черта у меня не вышло, в связи с JavaScript-related заморочками (впрочем, сайт тот загнулся сам по себе). А жаль, с точки зрения нагрузки на сервер этот вариант потянул бы на идеальный, если бы оказался действительно работоспособным.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Прежде чем я расскажу, как дошёл до такой жизни, хочу заметить, что убедить меня отказаться от этого решения можно только одним способом: предложив не менее компактную на уровне исходников и не менее удобную для использования альтернативу. Оптимизировать в ущерб компактноти кода я не намерен. Кто заговорит про требования по производительности, первым делом получит предложение переехать с php на java, а вторым — пойти куда подальше.
Даже если это будет пользователь?
Даже если на форумах напишут: "А вот программа конкурента делает все то же самое, но работает вчетверо быстрее"?
Если у тебя цель — компактность кода, то тогда ты прав. Но это не самая распространенная цель обычно.
Здравствуйте, jazzer, Вы писали:
J>Даже если это будет пользователь? J>Даже если на форумах напишут: "А вот программа конкурента делает все то же самое, но работает вчетверо быстрее"?
Для PHP? Смеёшься?
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, jazzer, Вы писали:
J>>Даже если это будет пользователь? J>>Даже если на форумах напишут: "А вот программа конкурента делает все то же самое, но работает вчетверо быстрее"? C>Для PHP? Смеёшься?
Пользователю пофиг, что на чем написано, ему функциональность нужна.
Здравствуйте, jazzer, Вы писали:
J>>>Даже если это будет пользователь? J>>>Даже если на форумах напишут: "А вот программа конкурента делает все то же самое, но работает вчетверо быстрее"? C>>Для PHP? Смеёшься? J>Пользователю пофиг, что на чем написано, ему функциональность нужна.
Я к тому, что пользователям, используюшим PHP скорость как таковая не очень-то важна. Если работает быстрее секунды — то всё нормально.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, jazzer, Вы писали:
J>>>>Даже если это будет пользователь? J>>>>Даже если на форумах напишут: "А вот программа конкурента делает все то же самое, но работает вчетверо быстрее"? C>>>Для PHP? Смеёшься? J>>Пользователю пофиг, что на чем написано, ему функциональность нужна. C>Я к тому, что пользователям, используюшим PHP скорость как таковая не очень-то важна. Если работает быстрее секунды — то всё нормально.
Ну разве что...
Ну тогда это из серии "преждевременная оптимизация"
P.S. Ты вообще не спишь, что ли? В Киеве же полпятого утра сейчас
Здравствуйте, jazzer, Вы писали:
C>>Я к тому, что пользователям, используюшим PHP скорость как таковая не очень-то важна. Если работает быстрее секунды — то всё нормально. J>Ну разве что... J>Ну тогда это из серии "преждевременная оптимизация"
Именно.
J>P.S. Ты вообще не спишь, что ли? В Киеве же полпятого утра сейчас
Я только четыре часа назад проснулся
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, jazzer, Вы писали:
C>>>Я к тому, что пользователям, используюшим PHP скорость как таковая не очень-то важна. Если работает быстрее секунды — то всё нормально. J>>Ну разве что... J>>Ну тогда это из серии "преждевременная оптимизация" C>Именно.
но тогда и пользователи не будут возмущаться, а всех остальных можно отправлять по градиенту, если это не начальство, конечно, хотя его тоже иногда можно
И вообще, лучший индикатор нужности оптимизации: "А пользователь это заметит?"
J>>P.S. Ты вообще не спишь, что ли? В Киеве же полпятого утра сейчас C>Я только четыре часа назад проснулся
А, ты все еще практикуешь "два часа поспал — два часа поел"? И как оно на сегодняшний день?
Здравствуйте, jazzer, Вы писали:
C>>Именно. J>но тогда и пользователи не будут возмущаться, а всех остальных можно отправлять по градиенту, если это не начальство, конечно, хотя его тоже иногда можно J>И вообще, лучший индикатор нужности оптимизации: "А пользователь это заметит?"
Согласен.
C>>Я только четыре часа назад проснулся J>А, ты все еще практикуешь "два часа поспал — два часа поел"? И как оно на сегодняшний день?
Нет, у меня скорее 27-часовой день теперь
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Всем привет.
Вообще, XSLT исторически работал в режиме интерпретации. Что обеспечивало относительно низкую скорость преобразований.
Затем хитрые люди придумали, что можно ведь по XSLT сгенерировать код программы на языке высокого уровня, которой на вход подается некий IXPathNavigable, а на выходе — соответствующий текст, XML или HTML. Это позволяет существенно поднять скорость преобразований (т.к. программа потом компилируется в целевой код) даже без особых оптимизаций.
Чисто теоретически, умная среда исполнения должна уметь компилировать также и цепочку XSLT преобразований. Ведь если ты можешь выполнить "подстановку", то и программа сможет, не так ли? А значит ты можешь получить максимальную производительность при максимально компактном коде.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>Всем привет.
И вам, добрый человек, того же.
Интересно этом мне одному кажется что XSLT придумали больные люди?
Была такая мулечка одно время: "молодежь — на XML!"
Почему-то мне кажется что трансформации можно было бы описывать на языке гораздо более для того приспособленном чем XML.
Вообще это маразм использовать язык описания данных в роли процедурного. Или нет?
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, Дм.Григорьев, Вы писали:
ДГ>>Всем привет.
CS>И вам, добрый человек, того же.
CS>Интересно этом мне одному кажется что XSLT придумали больные люди? CS>Была такая мулечка одно время: "молодежь — на XML!" CS>
CS>Почему-то мне кажется что трансформации можно было бы описывать на языке гораздо более для того приспособленном чем XML. CS>Вообще это маразм использовать язык описания данных в роли процедурного. Или нет?
имхо, процедурное использование XSLT — это неправильное его использование.
Должно быть только описание правил преобразования, декларативно-функциональное, и все.
Этого должно быть достаточно для любых преобразований.
Здравствуйте, c-smile, Вы писали:
CS>Почему-то мне кажется что трансформации можно было бы описывать на языке гораздо более для того приспособленном чем XML.
Кто-то его здесь ругал в своё время чёрным матом. Агитировал за XQuery. Как по мне, лучше уж Scala — она статически типизирована. А XQuery — преимущество только в компактном синтаксисе. Но для PHP даже эта альтернатива недоступна. На PHP ради скорости можно юзать только одно: echo "<td>" . $obj->title() . "</td>". Но это фантастически быстро приводит к бардаку. Используя XSLT, я себя тупо дисциплинирую в плане разделения кода и представления.
Здравствуйте, Cyberax, Вы писали:
C>Я к тому, что пользователям, используюшим PHP скорость как таковая не очень-то важна. Если работает быстрее секунды — то всё нормально.
У меня сайты на одном ядре Core2 Duo 1800, DDR2 667 отрабатывают 10 запросов в секунду (замерялость тупым локальным for () do; wget; done). Как говорится, е#у и плачу.
Здравствуйте, jazzer, Вы писали:
J>имхо, процедурное использование XSLT — это неправильное его использование. J>Должно быть только описание правил преобразования, декларативно-функциональное, и все.
Какое угодно. Только human readable.
J>Этого должно быть достаточно для любых преобразований.
Статические преобразования не всегда эффективны.
Есть ситуации когда процедурный подход позволяет редуцировать complexity.
Иногда с O(n*n) до O(n). Все в общем как всегда — все хорошо что в меру.
Здравствуйте, Lloyd, Вы писали:
L>Второй и третий этап делать на этапе деплоймента сайта. На выходе должно получиться большое количество xslt первого типа.
Весьма хорошая идея, жаль я сам не додумался. Надо обмозговать преобразования на этапе сборки.