Прогулка / цикл через ключ 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>


Однако это не работает. Я просто хочу перечислить все значения в ключе для целей тестирования.

Вопрос прост: как это можно сделать?
649   4  

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'))"/>

Обратите внимание, что константой может быть любая строка или даже число - но " все " читается хорошо.

Однако вы не можете использовать этот ключ для поиска информации об отдельных записях (поскольку все они имеют одинаковое значение ключ).

Другими словами, существует два типа возможных ключей:
  1. "ключи поиска" = стандартные ключи с различными индексами в атрибуте use
  2. "циклические ключи" = ключи с константой в атрибуте use
Я не знаю, насколько эффективен этот метод для выполнения, однако он делает обслуживание XSL более эффективным, избегая повторения одного и того же (потенциально очень сложного) выражения XPath во всем коде XSL.

Вместо того чтобы думать о ключах 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. Таким образом:

Ключ Джони+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)

Таким образом, мы видим, что все 8 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

    Ничего не найдено.