В этом catalog.xml
файл. У меня есть две книги, у кого есть те же материально-технические ресурсы (т.е. 20). Я хочу записать файл XSL, который отобразит самое большое количество копий книги в каталоге. Если существует две или больше книги тех же материально-технических ресурсов затем, они должны быть отображены.
<catalog>
<Book>
<sku>12345</sku>
<title>Beauty Secrets</title>
<condition>New</condition>
<current_inventory>20</current_inventory>
<price>99.99</price>
</Book>
<Book>
<sku>54321</sku>
<title>Picturescapes</title>
<current_inventory>20</current_inventory>
<condition>New</condition>
<price>50.00</price>
</Book>
<Book>
<sku>33333</sku>
<title>Tourist Perspectives</title>
<condition>New</condition>
<current_inventory>0</current_inventory>
<price>75.00</price>
</Book>
<Book>
<sku>10001</sku>
<title>Fire in the Sky</title>
<condition>Used</condition>
<current_inventory>0</current_inventory>
<price>10.00</price>
</Book>
</catalog>
Ниже мой catalog3.xsl
файл, который может отобразить только один из двух книг:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:variable name="max"/>
<xsl:template match="/">
<html>
<body>
<h2>Titles of Books for which Most Copies are Available</h2>
<table border="2">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>No of Copies</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="catalog">
<xsl:for-each select="Book">
<xsl:sort select="current_inventory" data-type="number" order="descending"/>
<tr>
<xsl:if test="position()= 1">
<p><xsl:value-of select="$max = "/></p>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="current_inventory"/></td>
</xsl:if>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Мог кто-либо исправлять меня для достижения моей цели отображения всех копий, имеющих те же максимальные материально-технические ресурсы в каталоге.Спасибо.
Максимальный current_inventory
можно рассчитать следующим образом:
<xsl:variable name="max">
<xsl:for-each select="/catalog/Book/current_inventory">
<xsl:sort data-type="number" order="descending"/>
<xsl:if test="position()=1"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
</xsl:variable>
Регулировка критериев для xsl: if
для сравнения current_inventory
текущего узел в для каждого
в переменную $ max
достигает желаемого результата.
Вы оценивали position () = 1
внутри для каждого
, что будет верно только для первого элемента в отсортированной коллекции.
Я настроил его на поиск current_inventory
, который равен $ max
:
<xsl:if test="current_inventory = $max">
Применение этих изменений к вашей таблице стилей :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--Determine the maximum current_inventory -->
<xsl:variable name="max">
<xsl:for-each select="/catalog/Book/current_inventory">
<xsl:sort data-type="number" order="descending"/>
<xsl:if test="position()=1"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<html>
<body>
<h2>Titles of Books for which Most Copies are Available</h2>
<table border="2">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>No of Copies</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="catalog">
<xsl:for-each select="Book">
<xsl:sort select="current_inventory" data-type="number" order="descending"/>
<xsl:if test="current_inventory = $max">
<tr>
<td>
<xsl:value-of select="title"/>
</td>
<td>
<xsl:value-of select="current_inventory"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</xsl:template>
Вот решение с использованием мюнхианской группировки:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kBookByNums"
match="Book" use="number(current_inventory)"/>
<xsl:template match="/*">
<xsl:for-each select=
"Book
[generate-id()
=
generate-id(key('kBookByNums',
number(current_inventory)
)[1]
)
]
">
<xsl:sort select="current_inventory"
data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:copy-of select=
"key('kBookByNums',
number(current_inventory)
)"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к предоставленному XML-документу, получается правильный результат:
<Book>
<sku>12345</sku>
<title>Beauty Secrets</title>
<condition>New</condition>
<current_inventory>20</current_inventory>
<price>99.99</price>
</Book>
<Book>
<sku>54321</sku>
<title>Picturescapes</title>
<current_inventory>20</current_inventory>
<condition>New</condition>
<price>50.00</price>
</Book>
Обновление:
Может показаться, что это решение xsl-key "разыгрывает свою "карту эффективности" только для больших входных документов (т.е. тысяч книг). ", как кто-то выразился. На самом деле, такое утверждение весьма неточно.
Улучшение эффективности может быть большим даже при не очень большом количестве элементов, если число различных значений очень мало по сравнению с общим числом значений. Таким образом, даже для довольно небольших наборов предметов (одна-две сотни) существует значительный эффект, если число различных значений не превышает 10-20 - то, что происходит во многих реальных случаях.
Важно лишь небольшое отношение числа различных значений к общему размеру.
Подобные вещи неприятны с XSL. Чтобы выяснить, «есть ли две или более книги одного и того же инвентаря» в разметке, когда подсчет инвентаря может быть произвольным, потребуется структура данных, в которой вы можете хранить количество встреченных инвентаризаций. Я бы предложил пройти по XML DOM перед преобразованием и рассчитывать на него (намного проще), а затем создать новый документ узлов, которые вы хотите преобразовать, и применить к нему XSL. Это будет проще и менее беспорядочно, чем пытаться добиться всего в таблице стилей.
Эта таблица стилей XSLT 1.0
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="catalog">
<!-- find the maximum <current_inventory> of all books -->
<xsl:variable name="MaxInventory">
<xsl:for-each select="Book">
<xsl:sort select="current_inventory" data-type="number" order="descending" />
<xsl:if test="position() = 1">
<xsl:value-of select="current_inventory" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- output all matching <Book>s, sorted by title -->
<table>
<xsl:apply-templates select="Book[current_inventory = $MaxInventory]">
<xsl:sort select="title" data-type="text" order="ascending" />
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="Book">
<tr>
<td><xsl:value-of select="title" /></td>
<td><xsl:value-of select="current_inventory" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
производит
<table>
<tr>
<td>Beauty Secrets</td>
<td>20</td>
</tr>
<tr>
<td>Picturescapes</td>
<td>20</td>
</tr>
</table>
Обратите внимание, что существует более эффективное решение, оно включает в себя ключи XSL (Димитр Новачев показывает это). Это просто и легко следовать, решение XSL-ключа является продвинутым и разыгрывает свою «карту эффективности» только для больших входных документов (т. Е. Тысяч книг). При небольших входных документах разница в производительности будет незначительной.