(Продолжение, начало см. в МК № 48, 51—52, 3, 5—7 (167, 170—171, 174, 176—178))

XML-технологии: фильтры XSL

В последних статьях мы рассмотрели некоторые возможности XSL, которые позволяют автоматизировать оформление документов XML, имеющих регулярную структуру. Напомню, что при форматировании исходного документа в виде таблицы мы использовали специальный элемент xsl:for-each для организации последовательного перебора узлов, подлежащих трансформации. Мы научились выводить в окне браузера таблицу с отсортированными по определенному полю записями, а также применять условное форматирование (элемент xsl:choose) к ее ячейкам. В практических задачах часто возникает необходимость фильтровать содержимое базы данных, оставляя на экране лишь ту информацию, которая удовлетворяет определенному критерию отбора. Такая постановка задачи является классической для реляционных баз данных, а желаемый эффект достигается путем использования запросов к одной или нескольким связанным таблицам. Если вы никогда не имели дело с базами данных, но на вашем компьютере установлена какая-нибудь версия Microsoft Access, вы можете легко научиться конструировать и выполнять запросы к реляционным таблицам. Нас же сейчас будут интересовать исключительно средства XSL, предназначенные для выборочного показа информации, содержащейся в документе XML.

Создадим файл filter.xml и занесем в него следующий текст:

<?xml version="1.0" ?> <?xml:stylesheet type="text/xsl" href="filter.xsl" ?> <books> <review> <author>Pushkin</author>is the author of <title>Ruslan and Ludmila</title> The author lived in <century>19</century>century the book costs <price>12</price>dollars </review> <review> <author>Lermontov</author>wrote<title>Hero of Our Time</title> in <century>19</century>century The price of the book:<price>8</price>dollars </review> <review> <author>Zhirinovskiy</author>has written<title>God Save Russia</title> it is a masterpiece of<century>21</century>century This great book costs <price>300</price>dollars </review> <review> <author>Monika Levinsky</author>has written<title>A Good Time Spent with the President</title> she is a famous writer of <century>20</century>century <price>100</price>dollars is the price of the book </review> </books>

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

<?xml version='1.0'?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <html> <body bgcolor="#FFCC00"> <table border="2" bgcolor="#00FFFF" align="center"> <tr> <th>Author</th> <th>Title</th> <th>Century</th> </tr> <xsl:for-each select="books/review[author='Pushkin']"> <tr> <td><xsl:value-of select="author"/></td> <td><xsl:value-of select="title" /></td> <td><xsl:value-of select="century"/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>

Открыв файл filter.xml в окне Internet Explorer, вы увидите таблицу HTML, содержащую лишь одну запись. Принцип работы XSL в данном случае прост. В стилевой таблице мы использовали устаревшее пространство имен

xmlns:xsl="http://www.w3.org/TR/WD-xsl"

Это чтобы обеспечить тем пользователям, у которых не установлена специальная программа-анализатор, возможность просматривать в окне Internet Explorer 5.0 результат слияния файла XML с документом XSL.

Ключевым элементом документа filter.xsl является тэг XSLT:

<xsl:for-each select="books/review[author='Pushkin']">

который обеспечивает прохождение в цикле тех элементов review исходного документа XML, для которых содержимое узла author равно ‘Pushkin’. Это слово заключено в одинарные кавычки, так как существуют внешние двойные кавычки, между которыми оно находится. С кавычками вообще следует обращаться осторожно. Следите за тем, чтобы ваши двойные кавычки выглядели точно так же, как и мои, иначе возможны проблемы с визуализацией документа. Обратите внимание, что значением параметра select является выражение XPath, позволяющее локализовать узлы, которые подлежат форматированию. В приведенном примере квадратные скобки заключают в себе выражение XPath, служащее для уточнения множества перебираемых в цикле узлов. Что касается выражений, то XPath позволяет строить достаточно Таблицасложные арифметико-логические конструкции, дающие возможность разработчику стилевых таблиц писать нетривиальные запросы к XML-документам. Читатели, знакомые с языком структурированных запросов SQL, несомненно, найдут некоторое сходство между средствами этого языка и XPath. Покажем основные операции, которые служат «строительными кирпичиками» для выражений XPath, используемых в запросах (см. табл.).

Знаки < и <= в документах XSL нельзя использовать непосредственно в тексте. Для вставки таких операций в документ знак < следует менять на стандартную сущность < (lt — сокращение от «less than»; не забывайте ставить точку с запятой после этой аббревиатуры). Предположим, в нашем примере требуется вывести сведения о книгах, цена которых находится в промежутке от десяти до ста двадцати долларов. Тогда строку

<xsl:for-each select="books/review[author='Pushkin']">

нужно заменить на элемент

<xsl:for-each select="books/review[price>=10 and price &lt;=120]">.

Наконец, построим запрос, выводящий сведения о книгах XIX и XXI века, цена которых больше $10. Для этого придайте атрибуту select элемента xsl:for-each значение

"books/review[(century=19 or century=21) and price>10]"

Внеся необходимые изменения в файл filter.xsl, сохраните его и откройте файл filter.xml в окне Internet Explorer. Получится картинка приблизительно такая, как показано на рисунке.

Мне осталось лишь отметить, что к этому же результату приводит и использование конструкции XSL со специальным элементом xsl:if. Чтобы посмотреть, как работает этот элемент, замените соответствующую часть документа filter.xsl фрагментом

<xsl:for-each select="books/review"> <xsl:if match=".[(century=19 or century=21) and price>10]"> <tr> <td><xsl:value-of select="author"/></td> <td><xsl:value-of select="title" /></td> <td><xsl:value-of select="century"/></td> </tr> </xsl:if> </xsl:for-each>

(Продолжение следует)