KnigaRead.com/

Алексей Валиков - Технология XSLT

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Алексей Валиков, "Технология XSLT" бесплатно, без регистрации.
Перейти на страницу:

 result-prefix="#default"/>

означает, что элементы, принадлежащие в преобразовании пространству имен а, в выходящем документе должны принадлежать пространству имен по умолчанию. Определение вида

<xsl:namespace-alias

 stylesheet-prefix="#default"

 result-prefix="a"/>

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

Пример Листинг 8.17. Преобразование

<xsl:stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

 xmlns:a="urn:a"

 xmlns="urn:b">


 <xsl:namespace-alias

  stylesheet-prefix="#default"

  result-prefix="a"/>


 <xsl:namespace-alias

  stylesheet-prefix="a"

  result-prefix="#default"/>


 <xsl:template match="root">

  <result>

   <a:element/>

  </result>

 </xsl:template>


</xsl:stylesheet>

Листинг 8.18. Выходящий документ

<result xmlns="urn:a" xmlns:a="urn:b">

 <a:element/>

</result>

Результатом этого преобразования является то, что пространство имен с URI "urn:а" стало пространством имен по умолчанию, а пространство имен с URI "urn:b" изменило префикс на а.

В преобразованиях можно объявлять несколько псевдонимов пространств имен при условии, что одно и то же пространство имен преобразования не должно быть объявлено элементами xsl:namespace-alias с одинаковым порядком импорта псевдонимом для различных пространств имен выходящего документа.

Пример

Если преобразование a.xsl содержит определение

<xsl:namespace-alias

 stylesheet-prefix="x"

 result-prefix="a"/>

а преобразование b.xsl — определение

<xsl:namespace-alias

 stylesheet-prefix="x"

 result-prefix="b"/>

где в обоих преобразованиях префикс x представляет одно пространство имен, а пространства имен a и b — разные, то преобразование a.xsl не сможет включать преобразование b.xsl и наоборот, потому что они будут иметь одинаковый порядок импорта и содержать элементы xsl:namespace-alias, назначающие разным пространствам имен одинаковые псевдонимы. В одном преобразовании такие псевдонимы также не имеют права встречаться. Если же подобное все же случилось, процессор может сигнализировать ошибку или использовать определение, которое было дано в преобразовании последним.

Совсем иначе обстоит дело с импортированием. При импортировании определения старших в порядке импорта преобразований могут переопределять определения младших преобразований. Таким образом, если преобразование a.xsl будет импортировать преобразование b.xsl, пространство имен x будет назначено псевдонимом пространству имен а и наоборот.

Ключи

Прежде чем мы приступим к разбору ключей, которые являются одной из самых мощных концепций языка XSLT, попробуем решить одну несложную задачку.

Листинг 8.19. Входящий документ

<items>

 <item source="a" name="A"/>

 <item source="b" name="B"/>

 <item source="a" name="C"/>

 <item source="c" name="D"/>

 <item source="b" name="E"/>

 <item source="b" name="F"/>

 <item source="c" name="G"/>

 <item source="a" name="H"/>

</items>

Пусть входящий документ представляет собой список объектов (элементов item), каждый из которых имеет имя (атрибут name) и источник (атрибут source). Требуется сгруппировать объекты по своим источникам и получить документ приблизительно следующего вида.

Листинг 8.20. Требуемый результат

<sources>

 <source name="a">

  <item source="a" name="A"/>

  <item source="a" name="C"/>

  <item source="a" name="H"/>

 </source>

 <source name="b">

  <item source="b" name="B"/>

  <item source="b" name="E"/>

  <item source="b" name="F"/>

 </source>

 <source name="c">

  <item source="c" name="D"/>

  <item source="c" name="G"/>

 </source>

</sources>

Первым шагом на пути решения этой задачи является формулировка в терминах XSLT предложения "сгруппировать объекты по своим источникам". Источник каждого объекта определяется его атрибутом source, значит множество объектов, принадлежащих одному источнику "а", будет определяться путем выборки

/items/item[@source='a']

Тогда для каждого элемента item в его группу войдут элементы, которые будут выбраны выражением

/items/item[@source=current()/@source]

Попробуем использовать этот факт в следующем шаблоне:

<xsl:template match="item">

 <source name="{@source}">

  <xsl:copy-of select="/items/item[@source=current()/@source]"/>

 </source>

</xsl:template>

Как и ожидалось, при применении этого правила к элементам item для каждого из них будет создана группа, принадлежащая тому же источнику, — уже хороший результат, но в условии требуется создать по группе не для каждого объекта, а для каждого источника. Чтобы достичь этого, можно создавать группу только для первого объекта, принадлежащего ей. Провести такую проверку опять же несложно: объект будет первым в группе тогда и только тогда, когда ему не предшествуют другие, элементы item, принадлежащие тому же источнику. Иначе говоря, создаем группы только для тех элементов, для которых выражение

preceding-sibling::item[@source-current()/@source]

будет возвращать пустое множество.

С небольшими добавлениями искомое преобразование целиком будет иметь вид.

Листинг 8.21. Преобразование

<xsl:stylesheet

 version="1.0"

 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


 <xsl:template match="items">

  <sources>

   <xsl:apply-templates/>

  </sources>

 </xsl:template>


 <xsl:template match="item">

  <xsl:choose>

   <xsl:when

    test="preceding-sibling::item[@source=current()/@source]"/>

   <xsl:otherwise>

    <source name="{@source}">

     <xsl:copy-of select="self::node()

      |following-sibling::item[@source=current()/@source]"/>

    </source>

   </xsl:otherwise>

  </xsl:choose>

 </xsl:template>

</xsl:stylesheet>

Бесспорно, решение было несложным, но довольно громоздким. Самым же узким местом в этом преобразовании является обращение к элементам item источника текущего элемента посредством сравнения атрибутов source.

Проблема совершенно стандартна для многих преобразований: нужно выбирать узлы по определенным признакам, причем делать это нужно как можно более эффективно. Хорошо, что в нашем документе было всего восемь элементов item, но представьте себе ситуацию, когда элементов действительно много.

Проблема, которую мы подняли, достаточно серьезна. Она состоит в оптимизации поиска узлов с определенными свойствами в древовидно организованной структуре.

Попробуем разобраться в смысле фразы "узел обладает определенными свойствами". Очевидно, это означает, что для этого узла выполняется некое логическое условие, иначе говоря, некий предикат обращается в "истину".

Однако какого именно типа условия мы чаще всего проверяем? Анализируя различные классы задач, можно придти к выводу, что в большинстве случаев предикаты являются равенствами — выражениями, которые обращаются в "истину" тогда и только тогда, когда некоторый параметр узла, не зависящий от текущего контекста, равен определенному значению. В нашем примере смысл предиката на самом деле состоит не в том, чтобы проверить на истинность выражение @source=current()/@source, а в том, чтобы проверить на равенство @source и current()/@source.

Если переформулировать это для общего случая, то нам нужно выбрать не те узлы, для которых истинно выражение A=B, скорее нужно выбрать те, для которых значение A равно значению B. Иначе говоря, узел будет идентифицироваться значением в своего свойства A. И если мы заранее вычислим значения свойств A, проблема поиска узлов в дереве сведется к классической проблеме поиска элементов множества (в нашем случае — узлов дерева) по определенным значениям ключей (в нашем случае — значениями свойств A).

Чтобы пояснить это, вернемся к нашему примеру: мы ищем элементы item со значением атрибута source, равным заданному. Свойством, идентифицирующим эти элементы, в данном случае будут значения их атрибутов source, которые мы можем заранее вычислить и включить в табл. 8.2.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*