Вместо того, чтобы думать о ключах 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 вручную количество уникальных ключей для перечисленного выше будет равно трем: Джони + 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. Таким образом:
Ключ Джонни + 1 удовлетворяет 4 узлам (1) idp2805696-- (2) idp4013568-- (3) idp2609728-- (4) idp4011648
Ключ Джони + 2 удовлетворяет 3 узлам (1) idp2808192-- (2) idp2612224-- (3) idp2610432-- (4)
Ключ Джони + 3 удовлетворяет 1 узел (1) idp2808640-- (2) - (3) - (4)
Таким образом, мы видим, что ВСЕ 8 cost
узлов XML могут быть доступны через ключ.
Вот изображение, которое объединяет результаты преобразования, чтобы лучше понять.
Красные квадраты обозначают совпадающие узлы для Джонни + 1 . Зеленые квадраты обозначают совпадающие узлы для Джони + 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. Слова узлы / записи / элементы используются взаимозаменяемо.