Главная » XSLT » Создание HTML-таблиц

0

Задача

Требуется преобразовать XML-документ в HTML-таблицы.

Решение

Таблицы часто создаются в два этапа. Сначала генерируется табличная раз­метка верхнего уровня, а затем для создания строк и ячеек применяются шаблоны.

Показанное ниже решение – это частичная модификация таблицы стилей из ре­цепта 10.2. Изменения выделены полужирным шрифтом:

<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html"/>

<xsl:param name="URL"/>

<xsl:template match="/">

<xsl:apply-templates select="*" mode="index"/> <xsl:apply-templates select="*" mode="content"/> </xsl:template>

<!– = = = = = = = = = = = = = = = = = — >

<!–  Создать index.html (mode = "index")              –>

<!– = = = = = = = = = = = = = = = = = — >

<xsl:template match="salesBySalesperson" mode="index">

<!– Нестандартный элемент xsl:document, реализованный в saxon! –>

<xsl:document href="index.html">

<html>

<head>

^^^>Продажи в разрезе продавцов</title> </head>

<body bgcolor="#FFFFFF" text="#000000"> <h1>Продажи в разрезе продавцов</h1> <xsl:apply-templates mode="index"/> </body> </html>

</xsl:document> </xsl:template>

<xsl:template match="salesperson" mode="index"> <h2>

<a href="{concat($URL,@name,’.html’)}">

<xsl:value-of select="@name"/> </a> </h2>

</xsl:template>

<!– = = = = = = = = = = = = = = = = = — >

<!–  Создать @name.html (mode = "content")            –>

<!– = = = = = = = = = = = = = = = = = — >

<xsl:template match="salesperson" mode="content">

<xsl:document href="{concat(@name,’.html’)}">

<html> <head>

<titleXxsl:value select="@name"/></title> </head>

<body bgcolor="#FFFFFF" text="#000000"> <h1Xxsl:value-of select="@name"/> Sales</h1> <table border="1" cellpadding="3"> <tbody > <tr>

<№>Поэиция</№> <№>Объем продаж (в US $)</th> </tr>

<xsl:apply-templates mode="content"/> </tbody> </table>

<h2Xa href="{concat($URL,’index.html’)}">Home</a></h2> </body>

</html> </xsl:document> </xsl:template>

<xsl:template match="product" mode="content"> <tr>

<tdXxsl:value-of select="@sku"/></td> <tdXxsl:value-of select="@totalSales"/></td> </tr>

</xsl:template>

</xsl:stylesheet>

Обсуждение XSLT 1.0

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

<?xml version="1.0" encoding="UTF-8"?> <sales>

<product sku="10000" sales="90000.00" region="NE"/> <product sku="10000" sales="10000.00" region="NW"/>

<product sku="10000" sales="55000.00" region="SE"/> <product sku="10000" sales="32000.00" region="SW"/> <product sku="10000" sales="95000.00" region="NC"/> <product sku="10000" sales="88000.00" region="SC"/> <product sku="20000" sales="77000.00" region="NE"/> <product sku="20000" sales="11100.00" region="NW"/> <product sku="20000" sales="33210.00" region="SE"/> <product sku="20000" sales="78000.00" region="SW"/> <product sku="20000" sales="105000.00" region="NC"/> <product sku="20000" sales="12300.00" region="SC"/> <product sku="30 0 0 0" sales="1000.00" region="NE"/> <product sku="30 0 0 0" sales="5100.00" region="NW"/> <product sku="30 0 0 0" sales="3210.0 0" region="SE"/> <product sku="30 0 0 0" sales="8000.00" region="SW"/> <product sku="30 0 0 0" sales="5000.00" region="NC"/> <product sku="30 0 0 0" sales="1130 0.0 0" region="SC"/>

</sales>

Здесь заранее известно, что есть шесть регионов. Поэтому задачу группиров­ки можно решить путем явного отбора:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/>

<xsl:template match="sales"> <html> <head>

<title>Пpoдaжи в paзpезе pегиoнoв</title> </head> <body>

<h1>Пpoдaжи в paзpезе pегиoнoв</h1> <table border="1" cellpadding="3"> <tbody> <tr>

<th>Пoзиция</th> <th>Пpoдaжи</th> </tr>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘NE’ "/> <xsl:with-param name="title" select="’North East Sales’"/> </xsl:call-template>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘NW’ "/> <xsl:with-param name="title" select="’North West Sales’"/> </xsl:call-template>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘NC’ "/> <xsl:with-param name="title" select="’North Central Sales’"/> </xsl:call-template>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘SE’ "/> <xsl:with-param name="title" select="’South East Sales’"/> </xsl:call-template>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘SC’ "/> <xsl:with-param name="title" select="’South Central Sales’"/> </xsl:call-template>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select=" ‘SW’ "/> <xsl:with-param name="title" select="’South West Sales’"/> </xsl:call-template> </tbody> </table> </body> </html> </xsl:template>

<xsl:template name="group-region"> <xsl:param name="region"/> <xsl:param name="title"/>

<xsl:variable name="products" select="product[@region = $region]" /> <tr>

<th colspan="2"><xsl:value-of select="$title" /></th> </tr>

<xsl:apply-templates select="$products"/> <tr style="font-weight:bold"> <td >Total</td> <td align="right"> <xsl:value-of

select="format-number(sum($products/@sales), ‘#.00′)"/>

</td> </tr> </xsl:template>

<xsl:template match="product"> <tr>

<td><xsl:value-of select="@sku"/></td> <td align="right"><xsl:value-of select="@sales"/></td> </tr>

</xsl:template> </xsl:stylesheet>

Если «зашивать» названия групп в код вам не нравится, примените таблично- управляемый подход:

<xsl:stylesheet version="1.0"

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

<sales:region code=_ QUOT?QUOT__ name="North East"/>

<sales:region code="NC" name="North Central"/> <sales:region code="NW" name="North West"/> <sales:region code="SE" name="South East"/> <sales:region code="SC" name="South Central"/> <sales:region code="SW" name="South West"/>

<xsl:variable name="products" select="/sales/product"/>

<xsl:output method="html"/>

<xsl:template match="sales"> <html> <head>

^^^>Продажи в разрезе регионов</title> </head> <body>

^1>Продажи в разрезе регионов</h1> <table border="1" cellpadding="3"> <tbody> <tr>

<th>Позиция</th> <th>Продажи</th> </tr>

<xsl:for-each select="document(”)/*/sales:region"> <tr >

<th colspan="2"><xsl:value-of select="@name"/> Продажи</^> </tr>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select="@code"/> </xsl:call-template> </xsl:for-each> </tbody> </table>

</body> </html> </xsl:template>

<xsl:template name="group-region"> <xsl:param name="region"/>

<xsl:apply-templates select="$products[@region=$region]"/> <tr style="font-weight:bold"> <td>Итoгo</td>

<td align="right"><xsl:value-of

select="format-number(sum($products[@region=$region]/@sales),’#.00′)"/> </td> </tr> </xsl:template>

<xsl:template match="product"> <tr>

<td><xsl:value-of select="@sku"/></td>

<td align="right"><xsl:value-of select="@sales"/></td> </tr> </xsl:template>

</xsl:stylesheet>

Разумеется, не все задачи группировки настолько просты. Пусть, например, нужно спроектировать таблицу стилей, которая будет использоваться нескольки­ми компаниями или подразделениями одной компании, у которых собственные соглашения об именовании регионов продаж. К этой задаче можно подойти с раз­ных сторон, но одним из самых эффективных является метод группировки Мюн­ха (названный в честь придумавшего его Стива Мюнха из корпорации Oracle), в котором используется комбинация ключей и идентификаторов:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sales="sales">

<xsl:output method="html"/>

<xsl:key name="region-key" match="product" use="@region"/>

<xsl:template match="sales"> <html> <head>

<title>Пpoдажи в разрезе peгиoнoв</title> </head> <body>

<Ъ1>Продажи в разрезе регионов</Ъ1> <table border="1" cellpadding="3"> <tbody> <tr>

<th>Позиция</th> <th>Sales</th> </tr>

<xsl:variable name="unique-regions" select="/sales

/product[generate-id(.) =

generate-id(key(‘region-key’,@region))] /@region"/> <xsl:for-each select="$unique-regions"> <tr>

<th colspan="2"><xsl:value-of select="."/> Sales</th>

</tr>

<xsl:call-template name="group-region">

<xsl:with-param name="region" select="."/>

</xsl:call-template> </xsl:for-each> </tbody> </table> </body> </html>

</xsl:template>

<xsl:template name="group-region"> <xsl:param name="region"/>

<xsl:apply-templates select="key(‘region-key’, @region)"/> <tr style="font-weight:bold"> <td >Total</td>

<td align="right"><xsl:value-of

select="format-number(sum(key(‘region-key’, @region)/@sales),’#.00′)"/> </td> </tr> </xsl:template>

<xsl:template match="product"> <tr>

<td><xsl:value-of select="@sku"/></td>

<td align="right"><xsl:value-of select="@sales"/></td> </tr>

</xsl:template>

По своей структуре это решение аналогично таблично-управляемому. Основ­ное различие в том, как определяется уникальный набор групп. В таблично-уп­равляемом случае множество регионов кодируется вручную в элементах sales:region. А в методе Мюнха для определения значений групп использует­ся ключ. Известно, что выражение key(‘region-key’,@region) возвращает набор узлов, соответствующих всем товарным позициям в регионе ©region. Из­вестно также, что функция generate-id возвращает уникальный идентифика­тор первого элемента в переданном ей наборе узлов. Таким образом, выражение [generate-id(.) = generate-id( key( ‘region-key’, ©region))] истинно только для первого элемента в каждой группе, и в данном случае это по­зволяет получить все уникальные регионы, составляющие группу. Наличие клю­ча заодно повышает эффективность работы других частей таблицы стилей, кото­рые ссылаются на товар по региону.

XSLT 2.0

Если вы не начали читать прямо с этой главы, то знаете, что в XSLT 2.0 выпол­нять группировку лучше всего с помощью команды xsl:for-each-group:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0"

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

<xsl:output method="html"/>

<xsl:template match="sales"> <html> <head>

^^^>Продажи в разрезе регионов</title> </head> <body>

<М>Продажи в разрезе регионов</М> <table border="1" cellpadding="3"> <tbody> <tr>

<№>Позиция</№>

<th>Продажи</th> </tr>

<xsl:for-each-group select="product" group-by="@region"> <tr>

<th colspan="2"><xsl:value-of select="."/> Продажи</th> </tr>

<xsl:apply-templates select="current-group()"/> <tr style="font-weight:bold"> ^d^H^ra^td^

<td align="right"><xsl:value-of

select="format-number(sum(current-group()/@sales),’#.00′)"/> </td> </tr>

</xsl:for-each-group>

</tbody> </table> </body> </html> </xsl:template>

<xsl:template match="product"> <tr>

<td><xsl:value-of select="@sku"/></td> <td align="right"><xsl:value-of select="@sales"/></td> </tr> </xsl:template>

</xsl:stylesheet>

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии