XSLT - отфильтровывать элементы, на которые нет ссылок на x - PullRequest
0 голосов
/ 23 апреля 2020

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

Источник XML содержит 2001 "зон". Не больше, не меньше.

Он также содержит любое количество устройств, которые размещены в этих зонах. Один конкретный c пример источника XML содержит 8800 таких устройств. В одной зоне может быть размещено несколько устройств.

Зона 0 является "нулевой зоной", что означает, что устройство, помещенное в эту зону, в настоящее время не назначено. Это означает, что количество реальных зон равно 2000.

Упрощенный источник XML:

<configuration>
  <zones>
    <zone id="0">
    ...
    <zone id="2000"/>
  </zones>
  <devices>
    <device addr="1">
      <zone>1</zone>
    </device>
    ...
    <device addr="8800">
      <zone>1</zone>
    </device>
  </devices>
</configuration>

Проблема, с которой мы столкнулись, состоит в том, что из 2000 используемых зон, чаще всего только приблизительно 200 из них содержат одно или несколько устройств. Мне нужно вычеркнуть неиспользуемые зоны. Для этого есть причины, которые только отвлекают от рассматриваемого вопроса, поэтому, если вы не возражаете, я не буду здесь подробно останавливаться.

В настоящее время эта проблема решена, например:

<xsl:for-each select="zones/zone[@id &gt; 0]">
  <xsl:when test="/configuration/devices/device[zone=current()/@id]">
    <xsl:call-template name="Zone"/>
  </xsl:when>
</xsl:for-each>

И это работает. Но в некоторых крупных проектах трансформация занимает абсолютные времена. Это связано с тем, что в псевдокоде это означает:

  for each <zone> in <zones>
    find any <device> in <devices> with reference to <zone>
    if found
      apply zone template
    endif
  endfor

С 2000 зонами для итерации - и каждая итерация, запускающая до 8800, ищет подходящее устройство - вы можете себе представить, что это занимает очень много времени.

Что касается сложных проблем, libxslt не предоставляет API для отчетов о ходе работ. Это означает, что в течение длительного времени наше приложение будет выглядеть замороженным, пока оно импортирует и конвертирует клиента XML.

У меня есть возможность безоговорочно записывать каждую зону, и при загрузке приложения из нашего (выходного) XML удалить или игнорировать любые зоны, в которых нет устройств, помещенных в них. И может оказаться, что это может быть единственный вариант, который у меня есть.

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

Мой вопрос к вам:

Есть ли у меня другие опции, которые гарантируют, что выход XML содержит только используемые зоны?

Я не против выполнить последующее преобразование XSLT. Я, например, думал, что возможно (?) Написать атрибут used="false" для каждого элемента <Zone> в моих выходных данных. Затем, когда я go на устройствах, я нахожу соответствующую зону в своем выводе XML (при условии, что она назначена / зона не равна нулю) и меняю ее на used="true". Затем выполните быстрое второе преобразование, чтобы удалить все зоны, которые имеют used="false".

Но могу ли я ссылаться на свои собственные выходные элементы во время преобразования XSLT и изменять его содержимое?

1 Ответ

1 голос
/ 23 апреля 2020

Вы сказали, что у вас есть своего рода преобразование идентичности, поэтому я бы использовал его в качестве отправной точки, плюс ключ:

<xsl:key name="zone-ref" match="device" use="zone"/>

и пустой шаблон

<xsl:template match="zones/zone[not(key('zone-ref', @id))]"/>

, который предотвращает unreferences zone s от копирования.

Или, если есть другие условия, то, например,

<xsl:template match="zones/zone[@id > 0 and not(key('zone-ref', @id))]"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...