XSLT к HTML с простым группировкой данных XML с использованием шаблонов вместо каждого
Вопрос
Я разговаривал с XSLT и включенным, поскольку я стал администратором SharePoint, он использует XSLT Olot для отображения данных списка. Я недавно начал использовать его для преобразования результатов базы данных, которые я преобразовал в XML с помощью метода расширения. Я пытаюсь произвести чистый HTML.
Моя первая попытка, работала нормально. Однако я использовал для каждого повсюда, с тех пор, как я прочитал, что это плохо. Я читаю кучу вещей об использовании клавиш, но я не мог понять это или получить его на работу. Поэтому я переписал этот стиль листа ниже к тому, который находится под ним. Он использует шаблоны без для каждого.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<link rel="Stylesheet" type="text/css" href="../styles/BoxReportStyle.css" />
</head>
<body>
<span class="BoxReport">
<h2>Checked Out Boxes by Department with Transaction History</h2>
Count=<xsl:value-of select="count( /CheckedOutBoxes/row ) "/>
<!-- Get the divisions, since we are groing to group by division-->
<xsl:variable name="DivisionList" select="/CheckedOutBoxes/row[ not( Division = preceding-sibling::row/Division ) ]/Division" />
<xsl:for-each select="$DivisionList">
<xsl:variable name="DivisionName" select="." />
<h3>
<xsl:value-of disable-output-escaping="yes" select="$DivisionName "/>
</h3>
<!-- Get the list of departments, so we can group by department -->
<xsl:variable name="DepartmentList" select="/CheckedOutBoxes/row[ Division = $DivisionName and not( Department = preceding-sibling::row/Department) ]/Department" />
<xsl:for-each select="$DepartmentList">
<xsl:variable name="DepartmentName" select="." />
<h4>
<xsl:value-of disable-output-escaping="yes" select="$DepartmentName"/>
</h4>
<xsl:variable name="Rows" select="/CheckedOutBoxes/row[ Division = $DivisionName and Department = $DepartmentName ]" />
<!-- Start displaying the checked out box information for this division and department -->
<table>
<th>Box Number</th>
<th>Status Name</th>
<th>Entry Date</th>
<th>Description</th>
<xsl:for-each select="$Rows">
<tr>
<td>
<xsl:value-of select="BoxNumber"/>
</td>
<td>
<xsl:value-of select="StatusName"/>
</td>
<td>
<xsl:value-of select="EntryDate"/>
</td>
<td width="200px">
<xsl:value-of disable-output-escaping="yes" select="Description"/>
</td>
</tr>
<!-- Now display the transaction history if there is any-->
<xsl:if test=" count( Transaction ) > 0 ">
<tr>
<td></td> <!-- One blank row to shift things over-->
<td colspan="3">
<!-- Display transaction table-->
<table class="SubTable">
<th>Transaction Date</th>
<th>Requestor</th>
<th>Comments</th>
<xsl:for-each select="Transaction" >
<tr>
<td>
<xsl:value-of select="TransactionDate"/>
</td>
<td>
<xsl:value-of select="Requestor"/>
</td>
<td width="200px">
<xsl:value-of disable-output-escaping="yes" select="Comments"/>
</td>
</tr>
</xsl:for-each>
</table>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</xsl:for-each>
</xsl:for-each>
</span>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Теперь я переписал это к этому:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<link rel="Stylesheet" type="text/css" href="../styles/BoxReportStyle.css" />
</head>
<body>
<span class="BoxReport">
<h2>Checked Out Boxes by Department with Transaction History</h2>
Count=<xsl:value-of select="count( /CheckedOutBoxes/row ) "/>
<xsl:apply-templates mode="Division" select="/CheckedOutBoxes/row[ not( Division = preceding-sibling::row/Division ) ]"></xsl:apply-templates>
</span>
</body>
</html>
</xsl:template>
<xsl:template mode="Division" match="row">
<h3>
<xsl:value-of select="Division" disable-output-escaping="yes"/>
</h3>
<xsl:variable name="DivisionName" select="Division" />
<xsl:apply-templates mode="Department" select="/CheckedOutBoxes/row[ Division = $DivisionName and not( Department = preceding-sibling::row/Department ) ]"></xsl:apply-templates>
</xsl:template>
<xsl:template mode="Department" match="row">
<h4>
<xsl:value-of select="Department" disable-output-escaping="yes"/>
</h4>
<xsl:variable name="DivisionName" select="Division" />
<xsl:variable name="DepartmentName" select="Department" />
<table>
<th>Box Number</th>
<th>Status Name</th>
<th>Entry Date</th>
<th>Description</th>
<xsl:apply-templates mode="row" select="/CheckedOutBoxes/row[ Division = $DivisionName and Department = $DepartmentName ]" ></xsl:apply-templates>
</table>
</xsl:template>
<xsl:template mode="row" match="row">
<tr>
<td>
<xsl:value-of select="BoxNumber"/>
</td>
<td>
<xsl:value-of select="StatusName"/>
</td>
<td>
<xsl:value-of select="EntryDate"/>
</td>
<td width="200px">
<xsl:value-of disable-output-escaping="yes" select="Description"/>
</td>
</tr>
<!-- Display Transaction stuff as another row if we have any -->
<xsl:if test=" count( Transaction ) > 0 ">
<tr>
<td></td><!-- Shift the transaction over-->
<td colspan="3">
<!-- Start Transaction Table -->
<table class="SubTable">
<th>Transaction Date</th>
<th>Requestor</th>
<th>Comments</th>
<xsl:apply-templates select="Transaction">
<xsl:sort order="descending" select="TransactionDate"/>
</xsl:apply-templates>
</table>
</td>
</tr>
</xsl:if>
</xsl:template>
<xsl:template match="Transaction">
<tr>
<td>
<xsl:value-of select="TransactionDate"/>
</td>
<td>
<xsl:value-of select="Requestor"/>
</td>
<td width="200px">
<xsl:value-of disable-output-escaping="yes" select="Comments"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Я не включал ввод пример и вывод, так как все автоматически генерируется. Если это необходимо, я могу взять много времени и попытаться что-то произвести.
Мой вопрос в том, это лучший способ сделать это? Также, если ключевой способ лучше, может кто-то объяснить это или предоставить ссылку на хорошее объяснение?
Решение
В основном вопрос об использовании for-each
Вс. Шаблоны сводится к созданию многоразовых, более общих преобразований.
Используя шаблоны, все соответствующие узлы - нет только тех, которые явно используются в каждом - могут извлечь выгоду из шаблона, что помогает избежать дубликата кода и в то же время нарушает лист на более мелкие агрегаты, которые легче управлять. Это на самом деле в значительной степени так же, как иметь огромную процедуру или меньшие процедуры, вызывающие друг друга в императивном программировании.
Хотя некоторые люди предполагают, что использование шаблонов может работать лучше в некоторых двигателях, я считаю, что это не будет иметь значение.
Что сказал, вы можете узнать о Мюнченский метод (который использует ключевые ключи) для фактически группировки данных, где вы повторные ключи. Использование preceding-sibling
Ось очень медленная на некоторых двигателях, так что ей лучше избегать его, когда не обязательно не требуется.
Что-то вроде этого должно сделать трюк для подразделений (не тестированных):
<xsl:key name="divisions" match="/CheckedOutBoxes/row/Division" use="." />
...
<xsl:apply-templates mode="Division" select="/CheckedOutBoxes/Division[generate-id(.)=generate-id(key('divisions', .))]" />
Другие советы
Шаблон «для каждого» - это хорошая особенность XSLT.
Советы по использованию «шаблонов» вместо «для каждого» в основном о возможном неправильном использовании модели обработки XSLT.
В вашем примере ясно: один наивный «шаблон» и многие «для каждого», которые направляют процесс.
Использование ключа в самом XSLT о производительности. Его полезность заключается в замене выражений XPath, которые включают повторяющиеся путешествия на многие узлы входного дерева. MUENCHIAN Способ группировки - это специальное использование ключей. Простая группировка может быть оптимально без использования ключей.
С другой стороны, население - это особый случай преобразования. Я думаю, что лучше поддерживать, чтобы отделить семантику XHTML от преобразования XSLT. Проверьте www.aranedabienesraises.com.ar в качестве примера.