Учебное пособие (1075724), страница 12
Текст из файла (страница 12)
2.22. Результат выполнения примера 2.11.Обратите внимание на элемент<xsl:copy-of select="* | text()"/>XPath-выражение в атрибуте select выбирает узлы элементов «*» илитекстовые узлы «text()». Благодаря «*» в выходной документ копируютсяэлементы «<b>Полужирный текст</b>» и «<i>Курсив</i>», а благодаря «text()»,копируется текст «Обычный текст».XPath-выражения с использованием оператора объединения множеств « | »часто применяются при копировании узлов.952.2.12 Расширения XSLTРасширения XSLT (XSLT extensions) – это технология, которая позволяетвызывать из XSLT-преобразования исполняемый код.Расширения реализуются различным образом в разных XSLT-процессорах.Единого стандарта на расширения не существует.
Но почти во всех процессорахвызов расширений производится с использованием пространств имен, как вследующем примере.Языки, с помощью которых расширяются XSLT-процессоры, могут бытьразличными. Если XSLT-процессор разработан на платформе Java, как правило,он расширяется с использованием Java-классов.XSLT-процессор, разработанный Microsoft, может быть расширен спомощью языков сценариев (например, JavaScript) или с помощью языков,применяемых в .NET-платформе.В следующем примере в XSLT-преобразовании вызывается функция наязыке JavaScript.Пример 2.12.Файл XSLT:<?xml version="1.0" encoding="Windows-1251"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:msxsl="urn:schemas-microsoft-com:xslt"xmlns:user="http://ns1.org"><xsl:template match="/"><HTML><BODY><TABLE BORDER="2"><TR><TH>№</TH><TH>Язык разметки</TH>96<TH>Год создания</TH><TH>Возраст технологии (лет)</TH></TR><xsl:for-each select="languages/language"><TR><TD><xsl:value-of select="@id"/></TD><TD><xsl:value-of select="name"/></TD><TD><xsl:value-of select="year"/></TD><!-- Вызов функции в процессе преобразования --><!-- С помощью функции XPath "number" содержимое элементапреобразуется в число --><TD><xsl:value-of select="user:count_howold(number(howold))"/></TD></TR></xsl:for-each></TABLE></BODY></HTML></xsl:template><msxsl:script language="JavaScript" implements-prefix="user">//Функция возвращает значение, умноженное на 3function count_howold(howold_param){var res = howold_param * 3;return res;}</msxsl:script></xsl:stylesheet>Просмотр результата в браузере:97Рис.
2.23. Результат выполнения примера 2.12.Поскольку расширение использует особенности XSLT-процессора Microsoft,то оно будет работать только под Internet Explorer.Рассмотрим более подробно, как вызывается расширение.<?xml version="1.0" encoding="Windows-1251"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:msxsl="urn:schemas-microsoft-com:xslt"xmlns:user="http://ns1.org">В элементе stylesheet кроме стандартного для XSLT пространства имен спрефиксом xsl, объявлено пространство имен с префиксом msxsl для вызоварасширений на JavaScript.Также объявлено пространство имен с префиксом user для вызовапользовательских функций. Название "http://ns1.org" может быть произвольным.<xsl:value-of select="user:count_howold(number(howold))"/>В XPath-выражении производится вызов функции count_howold, написаннойна JavaScript.
Префикс «user:» указывает пространство имен, к которомуотносится эта функция. С помощью функции XPath «number» содержимое98элемента howold преобразуется в число, это значение передается функции вкачестве параметра.<msxsl:script language="JavaScript" implements-prefix="user">//Функция возвращает значение, умноженное на 3function count_howold(howold_param){var res = howold_param * 3;return res;}</msxsl:script>Элемент msxsl:script используется для создания расширения на языкахсценариев в XSLT-процессоре Microsoft.Атрибут language="JavaScript" определяет язык сценария.Атрибут implements-prefix="user" определяет префикс пространства имен,через который вызываются пользовательские функции. В нашем случае вызовфункции производится через префикс «user:»<xsl:value-of select="user:count_howold(number(howold))"/>Обратите внимание, что комментарий//Функция возвращает значение, умноженное на 3может быть записан не по правилам XML, а по правилам JavaScript, так какон находится внутри msxsl:script.Функция count_howold, написанная на JavaScript, возвращает параметр,умноженный на три.С использованием расширений XSLT могут быть решены две нестандартныезадачи:1.
XSLT можно превратить из средства преобразования данных в средствозагрузки данных. Например, если написать расширение, которое будетосуществлять вставку данных в БД, то данные можно не преобразовывать вдругой формат, а загружать в БД.992. Преобразование данных из XML в двоичный формат. Например, еслинаписать расширение, которое будет добавлять данные в двоичный файл, тоданные можно преобразовывать из XML в двоичный формат.2.2.13 Использование ключей поискаКлючи поиска в XSLT напоминают индексы в реляционной БД. Онипредназначены для поиска фрагментов документов по значению ключа.Ключ объявляется с помощью элемента XSLT<xsl:key name="название ключа" match="индексируемый узел" use="частьузла, которая является ключом" />Для поиска по ключу используется функция языка XPathkey("название ключа", "значение ключа, соответствующее атрибутуuse")Функция key возвращает множество узлов указанных в match, которыесоответствуют заданному значению ключа.Пример использования ключей:Пример 2.13.Файл XML:<?xml version="1.0" encoding="Windows-1251"?><?xml-stylesheet type="text/xsl" href="key.xsl"?><titles><book title="Книга про XML" author="Иванов"/><book title="Книга про HTML" author="Иванов"/><book title="Другая книга про XML" author="Петров"/><book title="Другая книга про HTML" author="Петров"/></titles>Файл XSLT:<?xml version="1.0" encoding="Windows-1251"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform">100<xsl:key name="title-search" match="book" use="@author"/><xsl:template match="/"><HTML><BODY><P><B>Книги автора Иванова:</B></P><xsl:for-each select="key('title-search', 'Иванов')"><P><xsl:number level="single" value="position()" format="1"/>.<xsl:value-of select="@title"/></P></xsl:for-each><P><B>Книги автора Петрова:</B></P><xsl:for-each select="key('title-search', 'Петров')"><P><xsl:number level="single" value="position()" format="I"/>.<xsl:value-of select="@title"/></P></xsl:for-each></BODY></HTML></xsl:template></xsl:stylesheet>Просмотр результата в браузере:101Рис.
2.24. Результат выполнения примера 2.13.Рассмотрим более подробно текст преобразования XSLT.<?xml version="1.0" encoding="Windows-1251"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:key name="title-search" match="book" use="@author"/>Объявлениеключасназваниемtitle-search.Индексируетсяэлементдокумента book, функция key будет возвращать именно эти элементы. Ключомявляется атрибут author элемента book.Обратите внимание, что XPath-выражение в атрибуте use вычисляется внутриконтекста, указанного в атрибуте match.<xsl:template match="/"><HTML><BODY><P><B>Книги автора Иванова:</B></P><xsl:for-each select="key('title-search', 'Иванов')">102Функция key вызывается для ключа 'title-search', значением ключа является'Иванов'.
Функция вернет множество элементов book, у которых значениеатрибута author='Иванов'.<P><xsl:number level="single" value="position()" format="1"/>.Элемент number позволяет генерировать номера в выходном документе. Вэтом примере генерируется одноуровневая нумерация (level="single"), номерэлемента соответствует текущей позиции в цикле (value="position()"). Значениеатрибута format= "1" | "I", соответственно нумерация арабскими или римскимицифрами.Элементnumberтакжепозволяетреализовыватьмногоуровневуюнумерацию.<xsl:value-of select="@title"/>Так как функция key возвращает элементы book, они перебираются в циклеfor-each, то XPath-выражения в теле цикла должны строиться в контексте book.XPath-выражение @title возвращает атрибут title текущего элемента book.</P></xsl:for-each>Аналогично выводятся книги второго автора, функция key используется сдругим значением ключа поиска<P><B>Книги автора Петрова:</B></P><xsl:for-each select="key('title-search', 'Петров')"><P><xsl:number level="single" value="position()" format="I"/>.<xsl:value-of select="@title"/></P></xsl:for-each></BODY>103</HTML></xsl:template></xsl:stylesheet>2.2.14 Создание кросс-таблицыРассмотрим более сложный пример создания кросс-таблицы.
Этот пример несодержит новых команд XSLT, по сравнению с предыдущими примерами.Сложность создания кросс-таблицы состоит в том, что заголовки строк истолбцов формируются динамически на основе данных, также динамическиформируются значения ячеек.Еще одна сложность состоит в том, что необходимо использоватьгруппировку данных, которая не реализована в XSLT 1.0 явным образом.Пример 2.14.Файл XML:<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="crosstable.xsl"?><Institute><Data><Department>ИУ - 5</Department><Student>Иванов И.И.</Student><CourseName>Интернет-технологии</CourseName><Result>5</Result></Data><Data><Department>ИУ - 5</Department><Student>Иванов И.И.</Student><CourseName>Язык XML</CourseName><Result>5</Result></Data>104<Data><Department>ИУ - 7</Department><Student>Петров П.П.</Student><CourseName>Интернет-технологии</CourseName><Result>5</Result></Data><Data><Department>ИУ - 5</Department><Student>Сергеев С.С.</Student><CourseName>Язык XML</CourseName><Result>5</Result></Data></Institute>Файл с данными состоит из нескольких элементов Data с вложеннымиэлементами.
Элемент Department содержит название кафедры, элемент Student –имя студента, элемент CourseName – название курса, элемент Result – оценку.Необходимо в строках таблицы выдать список студентов, сгруппированныйпо кафедрам, в заголовках столбцов выдать список курсов. Если у студента естьоценка за курс, то она выводится на пересечении строки и столбца. При этом не увсех студентов обязательно есть оценки по всем курсам.Файл XSLT:<?xml version="1.0" encoding="Windows-1251"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><!-- Объявление ключей для группировки и поиска --><xsl:key name="CourseName" match="Data" use="CourseName"/><xsl:key name="Department" match="Data" use="Department"/><xsl:key name="Student" match="Data" use="concat(Department,Student)"/>105<xsl:key name="Res" match="Data" use="concat(Department, Student,CourseName)"/><xsl:template match="/"><!-- Правило обработки корневого элемента XML - документа --><HTML><BODY><TABLE BORDER="2"><TR><!-- Пустая ячейка соответствует первому столбцу --><TH/><xsl:for-each select="//Data[generate-id(.)=generateid(key('CourseName',CourseName))]"><xsl:sort select="CourseName" data-type="text"/><TH><xsl:value-of select="CourseName"/></TH></xsl:for-each></TR><xsl:for-each select="//Data[generate-id(.)=generateid(key('Department',Department))]"><xsl:sort select="Department" data-type="text"/><!-- Данные о кафедре --><xsl:variable name="var1" select="Department"/><TR><TH><xsl:value-of select="$var1"/></TH></TR><!-- Данные о студенте --><xsl:for-each select="//Data[generate-id(.)=generateid(key('Student',concat($var1, Student)))]"><xsl:sort select="Student" data-type="text"/><xsl:variable name="var2" select="Student"/><TR><TD><xsl:value-of select="$var2"/></TD><!-- Перебор предметов --><xsl:for-each select="//Data[generate-id(.)=generateid(key('CourseName',CourseName))]"><xsl:sort select="CourseName" data-type="text"/>106<xsl:variable name="var3" select="CourseName"/><!-- Получение по ключу элемента Data, который соответствует текущейкомбинации кафедры, студента и предмета --><xsl:variable name="res" select="key('Res',concat($var1, $var2,$var3))"/><TD><xsl:value-of select="$res/Result"/></TD></xsl:for-each></TR></xsl:for-each></xsl:for-each></TABLE></BODY></HTML></xsl:template></xsl:stylesheet>Просмотр результата в браузере:Рис.















