A shelter from pigs on the wing
DMZ
дневник заведен 09-08-2004
постоянные читатели [32]
3 CaHuTaPa, 517design, Arde, Art`Is, aviabaza, BlackDrago, CyberJoe, DeadMorozz, Depeche Mode, DMZ, d_r, Ewige, glv12 Marla Zinger, goldenandy, Grimble, Hydralisk, Jude, Katrine Himitsu, Leave-me-alone, MISTIK, My3a, Nash, Nicholas Hawkwood, Pingvin, Riskoff, VorteX DrAgON, Wolfram, Букля_, достало, Муть, Рика, Эль
закладки:
цитатник:
дневник:
местожительство:
Красноярск, Россия, Сибирь
интересы [24]
программирование, C++, Depeche Mode, Star Wars, perl, DVD, JavaScript, FAR, lost, 80е, Half Life 2, долго спать, Miami Vice, веб-роботы, кентаврицы
антиресы [9]
грибы, грейпфрутовый сок, мёртвые люди, табличка обед, долго спать
01-11-2006 13:45 XML, XSL, XPath
За ночь узнал поразительно много о сабже.
Вобщем была задача красиво отобразить некую 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) &lt; 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>



Ну вот такая лекция получилась.

Ваш комментарий:
Камрад:
Гость []
Комментарий:
[смайлики сайта]
Дополнительно:
Автоматическое распознавание URL
Не преобразовывать смайлики
Cкрыть комментарий
Закрыть