Что означает выражение $ data [not (key ('myKey' ,@myRef))] в XSLT? - PullRequest
0 голосов
/ 04 февраля 2020

Я читаю такие выражения

<xsl:variable name="myVar" select="$data[not(key('myKey',@myRef))]"/>

в устаревшем коде. Скорее всего это код от экспертов ;-). Мне интересно, что он делает, как он работает и как я могу восстановить его, чтобы сделать его более читабельным. Спасибо.

Ответы [ 2 ]

1 голос
/ 08 февраля 2020

У меня сейчас есть вариант использования. Нет, это не устаревший код. Это ясно из контекста и определения ключа и данных.

Если у нас есть такие данные:

<xsl:variable name="dict">
  <ITEMS>
    <ITEM id="1" content="it1">
      <ITEM-REF ref="3"/>
    </ITEM>
    <ITEM id="2" content="it2">
      <ITEM-REF ref="1"/>
    </ITEM>
    <ITEM id="3" content="it3">
      <ITEM-REF ref="6"/>
    </ITEM>
    <ITEM id="4" content="it4">
      <ITEM-REF ref="3"/>
    </ITEM>
    <ITEM id="5" content="it5">
      <ITEM-REF ref="5"/>
    </ITEM>
    <ITEM id="6" content="it6">
      <ITEM-REF ref="8"/>
    </ITEM>
    <ITEM id="7" content="it7">
      <ITEM-REF ref="9"/>
    </ITEM>
  </ITEMS>
</xsl:variable>

И мы хотим получить все элементы ITEM-REF со значениями @ref, где ITEM с таким же значением @id ( неработающие ссылки ) может помочь выражение:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" encoding="utf-8" indent="yes"/>

    <xsl:variable name="dict">
      <ITEMS>
        <ITEM id="1" content="it1">
          <ITEM-REF ref="3"/>
        </ITEM>
        <ITEM id="2" content="it2">
          <ITEM-REF ref="1"/>
        </ITEM>
        <ITEM id="3" content="it3">
          <ITEM-REF ref="6"/>
        </ITEM>
        <ITEM id="4" content="it4">
          <ITEM-REF ref="3"/>
        </ITEM>
        <ITEM id="5" content="it5">
          <ITEM-REF ref="5"/>
        </ITEM>
        <ITEM id="6" content="it6">
          <ITEM-REF ref="8"/>
        </ITEM>
        <ITEM id="7" content="it7">
          <ITEM-REF ref="9"/>
        </ITEM>
      </ITEMS>
    </xsl:variable>

    <xsl:key name="itemkey" match="ITEM" use="@id"/>

    <xsl:template match="START">
      <xsl:variable name="allItems" select="msxsl:node-set($dict)//ITEM"/>
      <xsl:variable name="allItemRefs" select="msxsl:node-set($dict)//ITEM-REF"/>
      <xsl:variable name="itemRefsNotReferencingOtherItems" select="$allItemRefs[not(key('itemkey',@ref))]"/>
      <REFERENCED-NOT-EXISTING>
        <xsl:for-each select="msxsl:node-set($itemRefsNotReferencingOtherItems)">
          <ITEM>
            <xsl:attribute name="id">
              <xsl:value-of select="@ref"/>
            </xsl:attribute>
          </ITEM>
        </xsl:for-each>
      </REFERENCED-NOT-EXISTING>
    </xsl:template>

  </xsl:stylesheet>

Вывод:

<?xml version="1.0" encoding="utf-8"?>
<REFERENCED-NOT-EXISTING>
  <ITEM id="8" />
  <ITEM id="9" />
</REFERENCED-NOT-EXISTING>

Ввод файл:

<?xml version="1.0" encoding="utf-8"?>
<START/>
0 голосов
/ 06 февраля 2020

Ключи являются важным аспектом XSLT. Вместо того, чтобы перестраивать их, лучше изучить концепцию.

Ключи можно понимать как таблицы с узлами, хранящимися под указанными c ключами. Они определены так:

<xsl:key name="addressByStreet" match="address" use="street"/>

Атрибут name - это просто QName (аналогично имени переменной). Атрибут match содержит выражение XPath, которое работает аналогично атрибуту match <xsl:template>. Когда процессор находит узел, который соответствует выражению, он оценивает выражение XPath атрибута use в контексте сопоставленного элемента. Если это выражение возвращает значения, они будут использоваться для создания новых записей в «таблице ключей» для соответствующего элемента.

Для иллюстрации этого: Приведенный выше ключ создает таблицу со всеми элементами <address> в обработанный документ, набранный по значению их <street> потомка. Это означает, что если у вас есть эти элементы:

<address>
  <street>Main Street</street>
  <number>123</number>
</address>
<address>
  <street>Main Street</street>
  <number>456</number>
</address>
<address>
  <street>Country Road</street>
  <street>Country Rd.</street>
  <number>789</number>
</address>

… вы можете использовать key('addressByStreet', 'Main Street') для получения всех перечисленных адресов на главной улице.

Вы можете использовать как key('addressByStreet', 'Country Road'), так и key('addressByStreet', 'Country Rd.') для получения последнего адреса.

Зачем здесь использовать ключи? Вышеупомянутое выражение может быть реализовано как //address[street='Main Street'], но теперь каждый раз, когда вызывается это выражение, процессор XSLT, вероятно, снова просматривает весь документ. Это проблема, если шаблон или l oop вызывается часто. Ключи могут иметь огромное преимущество в производительности (например, снизить сложность с O (n²) до O (n)), поскольку результаты «кэшируются».

Существует множество приложений и шаблонов, в которых используются ключи. Например, если у вас есть это XML:

<street-list>
  <street>Main Street</street>
  <street>Bumpy Road</street>
</street-list>

Выражение street-list/street[not(key('addressByStreet', .))] отфильтрует список улиц и вернет только улицы, для которых нет адреса в вышеприведенном списке, т.е. только "Bumpy Road" "в этом случае, потому что для" Main Street "существует ключевая запись.

Типичным применением ключей в XSLT 1 является мюнхенская группировка .

...