Добавление некоторых новых условий в XSLT-рекурсию - PullRequest
0 голосов
/ 18 января 2020

Вот существующий код XML -источника и XSLT-преобразования, который восстанавливает всю цепочку взаимосвязей родитель-потомок. Алгоритм выполняет правильную работу, но необходимо учитывать новые дополнительные условия; плюс выходные "строковые" (или имена) значения должны принимать более формализованную, правильную форму.

======= базовый источник

<root>
  <document ID-1="galaxyID"      ID-2="NULL"      ID-3="111" SHORTNAME="gal"  NAME="Milky Way"/>  <!-- this is parent's node -->
  <document ID-1="starID"        ID-2="galaxyID"  ID-3="222" SHORTNAME="st"   NAME="Sun"/>        <!-- this is subparent -->
  <document ID-1="planetID"      ID-2="starID"    ID-3="333" SHORTNAME="pl"   NAME="Earth"/>      <!-- this is subparent -->

  <document ID-1="africaID"      ID-2="planetID"  ID-3="aaa" SHORTNAME="сont" NAME="Africa"/>     <!-- child-1 -->
  <document ID-1="australiaID"   ID-2="planetID"  ID-3="bbb" SHORTNAME="сont" NAME="Australia"/>  <!-- child-2 -->
  <document ID-1="eurasiaID"     ID-2="planetID"  ID-3="ccc" SHORTNAME="сont" NAME="Eurasia"/>    <!-- child-3 -->
  <document ID-1="antarcticaID"  ID-2="planetID"  ID-3="ddd" SHORTNAME="сont" NAME="Antarctica"/> <!-- child-4 -->
</root>

======= = базовый xslt

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:key name="ref" match="document" use="@ID-1"/>

  <xsl:template match="document">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="key('ref', @ID-2)" mode="att"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="document" mode="att">
    <xsl:param name="pos" select="count(@*) + 1"/>
    <xsl:attribute name="attr-{$pos}">
      <xsl:value-of select="@NAME"/>
    </xsl:attribute>
    <xsl:apply-templates select="key('ref', @ID-2)" mode="att">
      <xsl:with-param name="pos" select="$pos + 1"/>
    </xsl:apply-templates>
  </xsl:template>

</xsl:stylesheet>

======== базовый выход

<?xml version="1.0" encoding="utf-16"?>
<root>
  <document ID-1="galaxyID" ID-2="NULL"     ID-3="111" SHORTNAME="gal" NAME="Milky Way" />
  <document ID-1="starID"   ID-2="galaxyID" ID-3="222" SHORTNAME="st"  NAME="Sun"   attr-6="Milky Way" />
  <document ID-1="planetID" ID-2="starID"   ID-3="333" SHORTNAME="pl"  NAME="Earth" attr-6="Sun" attr-7="Milky Way" />

  <document ID-1="africaID"     ID-2="planetID" ID-3="aaa" SHORTNAME="сont" NAME="Africa"     attr-6="Earth" attr-7="Sun" attr-8="Milky Way" />
  <document ID-1="australiaID"  ID-2="planetID" ID-3="bbb" SHORTNAME="сont" NAME="Australia"  attr-6="Earth" attr-7="Sun" attr-8="Milky Way" />
  <document ID-1="eurasiaID"    ID-2="planetID" ID-3="ccc" SHORTNAME="сont" NAME="Eurasia"    attr-6="Earth" attr-7="Sun" attr-8="Milky Way" />
  <document ID-1="antarcticaID" ID-2="planetID" ID-3="ddd" SHORTNAME="сont" NAME="Antarctica" attr-6="Earth" attr-7="Sun" attr-8="Milky Way" />
</root>

https://xsltfiddle.liberty-development.net/ncntCSJ/3

взаимосвязь схема

============================ НОВЫЕ ЦЕЛИ ========== ==================

1- Дополнительное условие внутри рекурсии

Наряду с каждым добавлением цикла проверка того, что каждый сравниваемый элемент имеет:

  • атрибут STATUS = 0

  • и атрибут ATTRIBUTE-NULL равен нулю (здесь это просто означает, что является атрибутом ATTRIBUTE-NULL внутри элемента, фактически)

2 - коррекция вывода строки

2.1 Конкатенация имен

Рекурсия образует целостную цепочку сущностей, поэтому их строковое объяснение - «Имена» могут быть объединены. Существует 2 уровня конкатенации:

a) конкатенация в пределах одного уровня [SHORTNAME] + [.] + [NAME] (конкатенация в одном элементе).

<EXAMPLE SHORTNAME="pl" NAME="Earth"/> --->> <EXAMPLE FULLNAME="pl. Earth"/>

b) сцепление между уровнями

<EXAMPLE FULLNAME="gal. Milky Way, st. Sun, pl. Earth, сont. Eurasia"/> <!-- note additional commas and dots -->

2.2 Номенклатура ограниченных выходных атрибутов в зависимости от уровней иерархии

В существующем XSLT-коде Переходные атрибуты с «именами» формируются случайным образом динамически c (подсчитывает номер позиции атрибута внутри элемента). В реальной ситуации постфикс цифри c может вырасти до третьей дюжины. Поэтому для улучшения ситуации может быть полезно реализовать ограниченный диапазон динамически генерируемых входящих атрибутов, привязанных только к числу уровней иерархии. Например:

<EXAMPLE LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="pl. Earth" LEVEL-4="сont. Eurasia"/>

2.3 RANK (атрибут)

RANK является последней контрольной точкой. Все восстановленные цепочки должны быть упорядочены по атрибуту RANK (он может совпадать с собственной рекурсией, но иногда нет. В любом случае атрибут RANK имеет более высокий приоритет. (Это правило также показано в предполагаемом выводе).

====== ИСТОЧНИК ЗАДАЧ

<root>
  <document ID-1="galaxyID"   ID-2="NULL"      ID-3="111" SHORTNAME="gal"  NAME="Milky Way" STATUS="0" RANK="1"/>
  <document ID-1="starID"     ID-2="galaxyID"  ID-3="222" SHORTNAME="st"   NAME="Sun"       STATUS="0" RANK="3"/>
  <document ID-1="planetID"   ID-2="starID"    ID-3="333" SHORTNAME="pl"   NAME="Earth"     STATUS="0" RANK="6"/>

  <document ID-1="africaID"      ID-2="planetID" ID-3="aaa" SHORTNAME="сont" NAME="Africa"     STATUS="0" RANK="8"/>
  <document ID-1="australiaID"   ID-2="planetID" ID-3="bbb" SHORTNAME="сont" NAME="Australia"  STATUS="0" RANK="8"/>
  <document ID-1="eurasiaID"     ID-2="planetID" ID-3="ccc" SHORTNAME="сont" NAME="Eurasia"    STATUS="0" RANK="9"/>
  <document ID-1="antarcticaID"  ID-2="planetID" ID-3="ddd" SHORTNAME="сont" NAME="Antarctica" STATUS="0" RANK="5"/>
  <!--note RANK! (higher than parent's "Earth" rank. So in the output they are switching )-->

  <document ID-1="atlantisID"    ID-2="planetID" ID-3="zzz" SHORTNAME="is"   NAME="Atlantis"   STATUS="2" NULL-ATTRIBUTE="some-value" RANK="8"/>
</root>

====== ПРЕДПОЛАГАЕМЫЙ ВЫХОД ЗАДАЧИ

<!-- ORDER NOTE:- not "continent-planet-star-galaxy" but "galaxy-star-planet-continent" -->

<root>
  <document ID-1="galaxyID"   ID-2="NULL"      ID-3="111" SHORTNAME="gal"  NAME="Milky Way" STATUS="0"  RANK="1"
                  FULLNAME="gal. Milky Way"
                  LEVEL-1="gal. Milky Way"/>
  <document ID-1="starID"     ID-2="galaxyID"  ID-3="222" SHORTNAME="st"   NAME="Sun"       STATUS="0"  RANK="3"
                  FULLNAME="gal. Milky Way, st. Sun"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun"/>
  <document ID-1="planetID"   ID-2="starID"    ID-3="333" SHORTNAME="pl"   NAME="Earth"     STATUS="0"  RANK="6"
                  FULLNAME="gal. Milky Way, st. Sun, pl. Earth"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="pl. Earth"/>

  <document ID-1="africaID"      ID-2="planetID" ID-3="aaa" SHORTNAME="сont" NAME="Africa"     STATUS="0" RANK="8"
                  FULLNAME="gal. Milky Way, st. Sun, pl. Earth, cont. Africa"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="pl. Earth" LEVEL-4="cont. Africa"/>
  <document ID-1="australiaID"   ID-2="planetID" ID-3="bbb" SHORTNAME="сont" NAME="Australia"  STATUS="0" RANK="8"
                  FULLNAME="gal. Milky Way, st. Sun, pl. Earth, cont. Australia"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="pl. Earth" LEVEL-4="cont. Australia"/>
  <document ID-1="eurasiaID"     ID-2="planetID" ID-3="ccc" SHORTNAME="сont" NAME="Eurasia"    STATUS="0" RANK="9"
                  FULLNAME="gal. Milky Way, st. Sun, pl. Earth, cont. Eurasia"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="pl. Earth" LEVEL-4="cont. Eurasia"/>
  <document ID-1="antarcticaID"  ID-2="planetID" ID-3="ddd" SHORTNAME="сont" NAME="Antarctica" STATUS="0" RANK="5"
                  FULLNAME="gal. Milky Way, st. Sun, cont. Antarctica, pl. Earth"
                  LEVEL-1="gal. Milky Way" LEVEL-2="st. Sun" LEVEL-3="cont. Antarctica" LEVEL-4="pl. Earth"/>
  <!--note! Earth and  Antarctica switching because of RANK-->
  <document ID-1="atlantisID"    ID-2="planetID" ID-3="zzz" SHORTNAME="is"   NAME="Atlantis"   STATUS="2" NULL-ATTRIBUTE="some-value" RANK="8" />
  <!-- nothing happens because of STATUS and NULL-ATTRIBUTE-->

</root>

вопрос какой код XSLT может быть применен для этого?

...