Ксдыщь!

Дилетантские заметки про XSLT/XPath, HTML/CSS и всякую фигню

XML шиворот-навыворот

13 февраля 2011 · XSLT/XPath, Рецептарий

Придумал и заодно решил тупую, но забавную задачку. Максимально развернуть входящий XML-документ. То есть из сорца вроде:

<alphabet-listing>
    <letter name000="A letter">
        <mark1_>Alfa Romeo</mark1_>
        <mark222>Aston Martin</mark222>
        <mark33333333>Audi</mark33333333>
    </letter>
    <!-- Тестовый коммент -->
    <test:letter name="B letter" xmlns:test="http://localhost">
        <mark>Bentley</mark>
        <mark>BMW</mark>
        <mark>Buick</mark>
    </test:letter>
    <letter test2:name="C letter" xmlns:test2="http://localhost2">
        <mark>Cadillac</mark>
        <mark>Chery</mark>
        <mark>Chevrolet</mark>
        <mark>Chrysler</mark>
        <mark>Citroen</mark>
    </letter>
    <letter name="D letter">
        <mark>Daewoo</mark>
        <mark>Daihatsu</mark>
        <mark>Dodge</mark>
    </letter>
</alphabet-listing>

Получить что-нибудь такое:

<gnitsil-tebahpla>
    <rettel eman="rettel D">
        <kram>egdoD</kram>
        <kram>ustahiaD</kram>
        <kram>ooweaD</kram>
    </rettel>
    <rettel auto-ns1:eman="rettel C" xmlns:auto-ns1="http://localhost2">
        <kram>neortiC</kram>
        <kram>relsyrhC</kram>
        <kram>telorvehC</kram>
        <kram>yrehC</kram>
        <kram>callidaC</kram>
    </rettel>
    <rettel eman="rettel B" xmlns="http://localhost">
        <kram xmlns="">kciuB</kram>
        <kram xmlns="">WMB</kram>
        <kram xmlns="">yeltneB</kram>
    </rettel>
    <!-- Тестовый коммент -->
    <rettel eman="rettel A">
        <kram>iduA</kram>
        <kram>nitraM notsA</kram>
        <_1kram>oemoR aflA</_1kram>
    </rettel>
</gnitsil-tebahpla>

Совершенно несмешная первоапрельская шутка, например. Заодно демонстрирует некоторые интересные штуки типа переворачивалки строки/порядка следования и создания NCName.

Комментарии о происходящем прямо по XSLT-коду. Читать дальше →

Передача булеан в ключ

5 февраля 2011 · XSLT/XPath, Рецептарий

Недавно увидел интересный вариант использования ключей. Вещь во многом бесполезная, но уж больно красивая как по мне.

<items>
    <item>Январь</item>
    <item>Февраль</item>
    <item>Март</item>
    <item>Апрель</item>
    <item>Май</item>
    <item>Июнь</item>
</items>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:key name="testMatch" match="item" use="contains(., 'р')"/>

    <xsl:template match="/">
        <result>
            <matched>
                <xsl:copy-of select="key('testMatch', 'true')"/>
            </matched>
            <not-matched>
                <xsl:copy-of select="key('testMatch', 'false')"/>
            </not-matched>
        </result>
    </xsl:template>
</xsl:stylesheet>
<result>
    <matched>
        <item>Январь</item>
        <item>Февраль</item>
        <item>Март</item>
        <item>Апрель</item>
    </matched>
    <not-matched>
        <item>Май</item>
        <item>Июнь</item>
    </not-matched>
</result>

Почему не передавать просто true()? Для меня это чисто стилистическая заморочка.

The use attribute is an expression specifying the values of the key; the expression is evaluated once for each node that matches the pattern. If the result is a node-set, then for each node in the node-set, the node that matches the pattern has a key of the specified name whose value is the string-value of the node in the node-set; otherwise, the result is converted to a string, and the node that matches the pattern has a key of the specified name with value equal to that string.

When the second argument to the key function is of type node-set, then the result is the union of the result of applying the key function to the string value of each of the nodes in the argument node-set. When the second argument to key is of any other type, the argument is converted to a string as if by a call to the string function
http://www.w3.org/TR/xslt#key

Такое вот в итоге явное приведение. Но key('testMatch', true()) тоже конечно работает. По крайней мере, в тех имплементациях, что есть под рукой.

Проверка на наличие текстового содержимого в элементе

23 декабря 2010 · XSLT/XPath, Рецептарий

С детства известно: если сожрал конфеты, то заворачивать камешки в фантик — последнее дело.

В данном случае разочаровывающий фантик выглядит примерно так:

<checks>
    <child></child>
    <child2>
        <grand>    </grand>
    </child2>
    <child3>
        <grand>
            <grand attribute-we-dont-care-about="some value">
                <grand>

                </grand>
            </grand>
        </grand>
    </child3>
    <child4>
        <grand>
            <grand attribute-we-dont-care-about="some value">
                <grand>
                    20
                </grand>
            </grand>
        </grand>
    </child4>
</checks>

Нас интересует только child 4, так как у него есть потомок, в значении которого есть что-то кроме вайтспейсов, а именно “20″. Конфета, другими словами. Читать дальше →

Еще один пост про группировку в XSLT 1.0

19 ноября 2010 · XSLT/XPath, Рецептарий

В этом посте мы рассмотрим, сюрприз, группировку посредством XSLT 1.0. Тема уже обжевана изрядно, но не лишать же мне вас удовольствия ознакомиться с ней и в этом уютном бложике.

Допустим, с сервера пришел совершенно бесталанный XML.

<marks>
    <mark>Buick</mark>
    <mark>Citroen</mark>
    <mark>Daewoo</mark>
    <mark>Chery</mark>
    <mark>Audi</mark>
    <mark>Chevrolet</mark>
    <mark>Alfa Romeo</mark>
    <mark>BMW</mark>
    <mark>Cadillac</mark>
    <mark>Daihatsu</mark>
    <mark>Aston Martin</mark>
    <mark>Dodge</mark>
    <mark>Bentley</mark>
    <mark>Chrysler</mark>
</marks>

Мы хотим из него получить алфавитный список, группированный по первой букве и отсортированный в нужном порядке:

<alphabet-listing>
    <letter name="A">
        <mark>Alfa Romeo</mark>
        <mark>Aston Martin</mark>
        <mark>Audi</mark>
    </letter>
    <letter name="B">
        <mark>Bentley</mark>
        <mark>BMW</mark>
        <mark>Buick</mark>
    </letter>
    <letter name="C">
        <mark>Cadillac</mark>
        <mark>Chery</mark>
        <mark>Chevrolet</mark>
        <mark>Chrysler</mark>
        <mark>Citroen</mark>
    </letter>
    <letter name="D">
        <mark>Daewoo</mark>
        <mark>Daihatsu</mark>
        <mark>Dodge</mark>
    </letter>
</alphabet-listing>

Для решения задачи нам потребуется метод, броско именуемый организованной преступной группировкой Мюнха. Читать дальше →

Разница между xsl:copy и xsl:copy-of

18 ноября 2010 · XSLT/XPath, Рецептарий

Постараюсь с минимумом воды раскрыть сабж. Итак, разница такова: xsl:copy-of осуществляет глубокое копирование (deep copy), а xsl:copy поверхностное (shallow copy).

Не особо непонятно? Заценим на примере.

Создадим перечень самых отстойных рок-альбомов 21 столетия:

<albums criteria="worst">
    <item id="1">
        <name>Chinese Democracy</name>
        <artist>Guns N' Roses</artist>
        <length>71:18</length>
        <label released="November 23, 2008">Geffen</label>
    </item>
    <item id="2">
        <name>Dark Horse</name>
        <artist>Nickelback</artist>
        <length>43:38</length>
        <label released="November 18, 2008">EMI</label>
    </item>
    <item id="3">
        <name>St. Anger</name>
        <artist>Metallica</artist>
        <length>75:01</length>
        <label released="June 5, 2003">Vertigo</label>
    </item>
</albums>

Теперь создадим xsl, который в точности копирует этот XML в результирующее дерево. Читать дальше →