Прогулка / цикл через ключ XSL: как?
Есть ли способ пройти через ключ и вывести все значения, которые он содержит?
<xsl:key name="kElement" match="Element/Element[@idref]" use="@idref" />
Я думал об этом так:
<xsl:for-each select="key('kElement', '.')">
<li><xsl:value-of select="." /></li>
</xsl:for-each>
Однако это не работает. Я просто хочу перечислить все значения в ключе для целей тестирования.
Вопрос прост: как это можно сделать?
4 ответов:
Вы не можете. это не то, для чего нужны ключи.
Вы можете перебирать каждый элемент в ключе, используя один вызов
key()тогда и только тогда, когда ключ каждого элемента одинаков.Если вам нужно перебрать все, над чем определен ключ, вы можете использовать выражение в атрибуте
match="..."вашего элемента<key>.Итак, если бы у вас был такой файл:
<root> <element name="Bill"/> <element name="Francis"/> <element name="Louis"/> <element name="Zoey"/> </root>И ключ, определенный следующим образом:
<xsl:key name="survivors" match="element" use="@name"/>Вы можете перебирать то, что использует ключ, используя содержание его атрибута
match:<xsl:for-each select="element"> <!-- stuff --> </xsl:for-each>Альтернативно, если каждый элемент имеет что-то общее:
<root> <element name="Bill" class="survivor"/> <element name="Francis" class="survivor"/> <element name="Louis" class="survivor"/> <element name="Zoey" class="survivor"/> </root>Тогда вы можете определить свой ключ следующим образом:
<xsl:key name="survivors" match="element" use="@class"/>И повторите все элементы следующим образом:
<xsl:for-each select="key('survivors', 'survivor')"> <!-- stuff --> </xsl:for-each>Потому что каждый элемент имеет общее значение "survivor" для атрибута
class.В вашем случае ваш ключ -
<xsl:key name="kElement" match="Element/Element[@idref]" use="@idref" />Таким образом, вы можете перебирать все, что у него есть, следующим образом:
<xsl:for-each select="Element/Element[@idref]"> <!-- stuff --> </xsl:for-each>
Вы можете создать ключ для использования в цикле-если вы просто укажете константу в атрибуте use ключевого элемента:
<xsl:key name="survivors" match="element" use="'all'"/>Затем можно выполнить цикл по всем элементам следующим образом:
<xsl:for-each select="key('survivors','all')"> ... </xsl:for-each>Или сосчитать их:
<xsl:value-of select="count(key('survivors','all'))"/>Обратите внимание, что константой может быть любая строка или даже число - но " все " читается хорошо.
Однако вы не можете использовать этот ключ для поиска информации об отдельных записях (поскольку все они имеют одинаковое значение ключ).
Другими словами, существует два типа возможных ключей:Я не знаю, насколько эффективен этот метод для выполнения, однако он делает обслуживание XSL более эффективным, избегая повторения одного и того же (потенциально очень сложного) выражения XPath во всем коде XSL.
- "ключи поиска" = стандартные ключи с различными индексами в атрибуте use
- "циклические ключи" = ключи с константой в атрибуте use
Вместо того чтобы думать о ключах XSL в терминах языка программирования, думайте о них как о наборах записей SQL. Это даст лучшее понимание. Для данного ключевого индекса, созданного как
<xsl:key name="paths" match="path" use="keygenerator()">Он может быть "повторен" / "пройден", как показано ниже
<xsl:for-each select="//path[generate-id()=generate-id(key('paths',keygenerator())[1])]">Чтобы понять это магическое число
[1], давайте рассмотрим следующий пример:Рассмотрим этот фрагмент XML
<root> <Person> <name>Johny</name> <date>Jan10</date> <cost itemID="1">34</cost> <cost itemID="1">35</cost> <cost itemID="2">12</cost> <cost itemID="3">09</cost> </Person> <Person> <name>Johny</name> <date>Jan09</date> <cost itemID="1">21</cost> <cost itemID="1">41</cost> <cost itemID="2">11</cost> <cost itemID="2">14</cost> </Person> </root>Преобразовано с помощью этого XSL.
<xsl:for-each select="*/Person"> <personrecords> <xsl:value-of select="generate-id(.)" />-- <xsl:value-of select="name"/>-- <xsl:value-of select="date"/>-- </personrecords> </xsl:for-each> <xsl:for-each select="*/*/cost"> <costrecords> <xsl:value-of select="generate-id(.)" />-- <xsl:value-of select="../name"/>-- <xsl:value-of select="../date"/>-- <xsl:value-of select="@itemID"/>-- <xsl:value-of select="text()"/> </costrecords> </xsl:for-each>Приведенное выше преобразование XSL перечисляет уникальный идентификатор узлов
Personи узловcostв видеidpxxxxxxx, как показано ниже.Давайте создадим ключ для записей1. <personrecords>idp2661952--Johny--Jan10-- </personrecords> 2. <personrecords>idp4012736--Johny--Jan09-- </personrecords> 3. <costrecords>idp2805696--Johny-- Jan10-- 1-- 34</costrecords> 4. <costrecords>idp4013568--Johny-- Jan10-- 1-- 35</costrecords> 5. <costrecords>idp2808192--Johny-- Jan10-- 2-- 12</costrecords> 6. <costrecords>idp2808640--Johny-- Jan10-- 3-- 09</costrecords> 7. <costrecords>idp2609728--Johny-- Jan09-- 1-- 21</costrecords> 8. <costrecords>idp4011648--Johny-- Jan09-- 1-- 41</costrecords> 9. <costrecords>idp2612224--Johny-- Jan09-- 2-- 11</costrecords> 10.<costrecords>idp2610432--Johny-- Jan09-- 2-- 14</costrecords>cost, используя комбинацию значенийnameиitemID.<xsl:key name="keyByNameItem" match="cost" use="concat(../name, '+', @itemID)"/>Вручную глядя на XML, число уникальных ключей для вышеизложенного будет равно трем: Johny+1, Джонни+2 и Джонни+3.
Теперь давайте протестируем этот ключ с помощью приведенного ниже фрагмента кода.<xsl:for-each select="*/*/cost"> <costkeygroup> <xsl:value-of select="generate-id(.)" />-- (1)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[1] ) " />-- (2)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[2] ) " />-- (3)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[3] ) " />-- (4)<xsl:value-of select="generate-id(key('keyByNameItem',concat(../name, '+', @itemID) )[4] ) " /> </costkeygroup> </xsl:for-each>И здесь является результатом:
Наш интерес заключается в том, чтобы попытаться понять важность1. <costkeygroup>idp2805696-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup> 2. <costkeygroup>idp4013568-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup> 3. <costkeygroup>idp2808192-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup> 4. <costkeygroup>idp2808640-- (1)idp2808640-- (2)-- (3)-- (4)</costkeygroup> 5. <costkeygroup>idp2609728-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup> 6. <costkeygroup>idp4011648-- (1)idp2805696-- (2)idp4013568-- (3)idp2609728-- (4)idp4011648</costkeygroup> 7. <costkeygroup>idp2612224-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup> 8. <costkeygroup>idp2610432-- (1)idp2808192-- (2)idp2612224-- (3)idp2610432-- (4)</costkeygroup>[1],[2],[3],[4]. В нашем случае генератором ключей являетсяconcat(../name, '+', @itemID).Для данного ключа,
[1]относится к первому появлению узла, который удовлетворяет генератору ключей. Аналогично[2]относится к второму появлению узла, удовлетворяющего генератору ключей. Таким образом[2],[3],[4], и т.д. являются ли все узлы, удовлетворяющие одному и тому же ключу, и, следовательно, могут рассматриваться дубликаты для данного ключа. Количество дубликатов зависит от входного XML. Таким образом:Таким образом, мы видим, что все 8Ключ Джони+1 удовлетворяет 4 узлы (1)idp2805696-- (2) idp4013568-- (3)idp2609728-- (4)idp4011648
Ключ Johny+2 удовлетворяет 3 узлы (1)idp2808192-- (2) idp2612224-- (3)idp2610432-- (4)
Ключ Johny+3 удовлетворяет 1 узел (1)idp2808640-- (2)-- (3)-- (4)costузлов XML могут быть доступны через ключ. Вот изображение, которое объединяет результаты преобразования, чтобы помочь лучше понять.Красные квадраты обозначают соответствующие узлы для Johny+1. Зеленые квадраты указывают соответствующие узлы для Johny+3 . Сопоставьте значения
idpxxxxxxxв<costkeygroup>со значениями в<costrecords>. Справка<costrecords>сопоставляет значенияidpxxxxxxxс источником XML.Вынос таков,
ключ XSL не фильтрует и не удаляет узлы. Все узлы, включая дубликаты, могут быть доступны через ключ. Таким образом, когда мы говорим "прохождение" ключа, нет понятия результирующего подмножества узлов из исходного набора узлов, доступных ключу для обработки.
Чтобы "пройтись" только по уникальным узлам ключа в приведенном выше примере пример, используйте
<xsl:for-each select="*/*/workTime[generate-id()=generate-id(key('keyByNameItem', concat(../name, '+', @itemID) )[1] ) ] ">
[1]означает, что первая запись для данного значения ключа обозначается как уникальная запись.[1]используется почти всегда, поскольку существует по крайней мере один узел, удовлетворяющий заданному значению ключа. Если мы уверены, что существует минимум 2 записи, удовлетворяющие каждому значению ключа в ключе, мы можем пойти дальше и использовать[2]для идентификации второй записи в наборе записей как уникальной записи.P. S используются слова узлы / записи / элементы попеременно.
Нет способа пройти через ключи, хотя мы можем вывести все значения, которые он содержит. В XSLT2 это гораздо проще, чем в XSLT1 (например, используя
fn:generate-idв соответствии с предыдущим ответом).Используя
fn:distinct-values<xsl:variable name="e" select="."/> <xsl:for-each select="distinct-values(Element/Element[@idref]/@idref)"> <li key="{.}"><xsl:value-of select="key('kElement', ., $e )" /></li> </xsl:for-each>Используя
xsl:for-each-group<xsl:for-each-group select="Element/Element[@idref]" group-by="@idref"> <li key="{current-grouping-key()}"><xsl:value-of select="current-group()" /></li> </xsl:for-each-group>

Comments