За ночь узнал поразительно много о сабже.
Вобщем была задача красиво отобразить некую XML. Список файлов с комментами.
Просто так браузеры его показывают как поппало. Opera - просто текст дампит. IE - раскрывающееся деревце рисует.
Вот для этого умные дядьки придумали XSL. Ну вроде как таблица стилей для XML.
Если на неё посмотреть по быстрому, то она просто позволяет преобразовывать XML теги в другие валидные XML-комбинации.
Так что можно спокойно XML конвертнуть в HTML, а точнее в XHTML.
При повторном взгляде открываются всякие интересные вещи типа переменных, шаблонов-макросов, условных операторов и прочего, что весьма плодотворствует полёту мысли.
Также можно пройти XML дважды. Например в первый раз вывести содержание файла, а при втором подходе собственно контент.
Ну например есть у нас XML
<book>
<chapter number="1" title="Глава первая. В которой ничего не проиходит">
Бла-бла-бла
</chapter>
<chapter number="2" title="Глава вторая. В которой что-то наверняка и произошло, но автор всё еще жж0т на тему природы">
Бла-бла-бла
</chapter>
</book>
Под это дело пишем XSL.
<xsl:template match="book">
<xsl:apply-templates select="chapter" mode="index"/>
<xsl:apply-templates select="chapter" mode="content"/>
</xsl:template>
<xsl:template match="chapter" mode="index">
<a href="#chapter_{@number}"><xsl:value-of select="@title"/></a>
</xsl:template>
<xsl:template match="chapter" mode="content">
<h2 id="#chapter_{@number}"><xsl:value-of select="@title"/></h2>
<p><xsl:value-of select="."/></p>
</xsl:template>
Раз! И у нас есть книжка с содержанием!
А теперь дальше в глубь. XPath
XPath это такя штука, которая служить для указания положения в XML-дереве, выборки некоторых множеств (например, всех дочерних элементов или родителя или всех тегов с заданым именем или всех дочерних с нужным значением атрибута), а еще есть минимальный набор функций.
Ну например...
child::* - все детки
child::comment - все дочерние теги коммент
descendants::* - дети и дети детей и.т.д.
child::chapter[position()=1] - первый тег chapters среди детей
child::chapter[position()=last()] - последняя глава
child::chapter[@author='Маяковский'] - главы за авторством Маяковского
child::chapter[contains(., 'Star Wars')] - все главы, которые упоминают Star Wars
<book name="Книга умных мыслей">
<chapter author="admin">Я сказал!</chapter>
<chapter author="moderator">Флуд</chapter>
</book>
Допустим мы находимся в контексте chapter[1]
@author вернёт "admin"
. => "Я сказал!"
../@name => "Книга умных мыслей" (на уровень вверх и аттрибут name)
following-sibling::*[position()=1]/@author => "moderator" (выбираем всех следущих братьев. Из них берем первого и берем аттрибут author)
Вот такая веселуха.
XPath юзается в аттрибуте select.
Ну и как я говорил, в XPath есть операторы и функции. Например остаток от деления
Мы находимся в контексте book:
<xsl:apply-templates select="chapter[(position() mod 2) = 0]"/>
Итак. Мы выбираем все chapter (child::chapter, child можно опускать), для каждого берем его позицию и делим на 2. Если у нас четный chapter, то остаток 0 и chapter включается в ответ.
Таким образом мы обработаем все четные главы.
[string-length(@author) < 5] - выберет все чаптеры с именем автора короче 5 символов.
Ну и так далее...
Если не хватает функций, то можно создать свою на основе существующих + часто юзается рекурсия.
Ну например напишем от нечего делать функцию сложения:
<xsl:template name="sum">
<xsl:param name="a"/> <!-- первый аргумент-->
<xsl:param name="b"/> <!-- второй аргумент-->
<xsl:value-of select="$a+$b"/> <!-- выводим в поток вывода-->
</xsl:template>
А вот функция сложения трех чисел. Используем наши наработки:
<xsl:template name="sum3">
<xsl:param name="a"/> <!-- первый аргумент-->
<xsl:param name="b"/> <!-- второй аргумент-->
<xsl:param name="c"/> <!-- третий аргумент-->
<xsl:variable name="s"> <!--выполняем нашу первую функцию sum, результат пишем в переменную s-->
<xsl:call-template name="sum>
<xsl:with-param name="a" select="$a"/>
<xsl:with-param name="b" select="$b"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$s+$c"/> <!--Окончательный ответ - s+c-->
</xsl:template>
Тут заодно есть и пример вызовы нашей функции.
Вообще значения можно передавать в select, если удаётся обойтися стандартом XPath:
<xsl:variable name="len" select="string-length(@author)">
<xsl:variable name="len" select="string-length(child::*[position()=last()]/@author)">
если надо использовать самописные функции, то делается так:
<xsl:variable name="len">
<!--вызов функции-->
</xsl:variable>
Ну вот такая лекция получилась.
Acer X960
[Print]
Гость