Получить общий идентификатор для всех предков от самого низкого члена - PullRequest
0 голосов
/ 31 января 2020

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

источник xml

<root>
  <Object id="top"                        uniq-id="001" status="0" rank="1"/>
  <Object id="middle"  id-parent="top"    uniq-id="020" status="0" rank="3"/>
  <Object id="middle"  id-parent="top"    uniq-id="021" status="1" rank="3"/>

  <!--   only the element with status="0" is considered -->

  <Object id="bottom-1"  id-parent="middle" uniq-id="111" status="1" rank="6" />
  <Object id="bottom-2"  id-parent="middle" uniq-id="222" status="1" rank="6" />
  <Object id="bottom-3"  id-parent="middle" uniq-id="333" status="0" rank="6" />  <!-- will be taken -->
  <Object id="bottom-4"  id-parent="middle" uniq-id="444" status="1" rank="6" />
  <Object id="bottom-5"  id-parent="middle" uniq-id="555" status="1" rank="7" />
  <Object id="bottom-6"  id-parent="middle" uniq-id="666" status="0" rank="7" />  <!-- will be taken -->
  <Object id="bottom-7"  id-parent="middle" uniq-id="777" status="1" rank="6" />
  <Object id="bottom-8"  id-parent="middle" uniq-id="888" status="1" rank="6" />
  <Object id="bottom-9"  id-parent="middle" uniq-id="999" status="0" rank="6" />  <!-- will be taken -->
</root>

начальный-xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:exslt="http://exslt.org/common">
  <xsl:key name="Object-By-id"        match="Object[(@status='0')]"  use="@id"/>
  <xsl:key name="Object-By-id-parent" match="Object[(@status='0')]"  use="string(@id-parent)"/>

  <xsl:variable name="fold-rtf">
    <xsl:apply-templates select="/" mode="fold"/>
  </xsl:variable>
  <xsl:variable name="folded-tree" select="exslt:node-set($fold-rtf)"/>

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

  <xsl:template match="Object[@status=0]/@*[last()]">
    <xsl:variable name="current" select=".."/>
    <xsl:copy/>
    <xsl:for-each select="$folded-tree">
      <xsl:for-each select="key('Object-By-id',$current/@id)">

        <!-- ====== !!  =======-->

        <xsl:if test="position()!=last()">
          <xsl:for-each select="ancestor-or-self::*">
            <xsl:attribute name="chain-id">
              <xsl:value-of select="@uniq-id"/>
            </xsl:attribute>
          </xsl:for-each>
        </xsl:if>

        <!-- ======= !! =======-->

      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="/|*" mode="fold">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="key('Object-By-id-parent',string(@id))" mode="fold">
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

результат (не корректный) https://xsltfiddle.liberty-development.net/94Acsm2/1

предполагаемый вывод

<root>
  <Object id="top"                          uniq-id="001" status="0" rank="1" chain-id="20"/>
  <Object id="middle"    id-parent="top"    uniq-id="020" status="0" rank="3" chain-id="20"/>

  <Object id="bottom-3"  id-parent="middle" uniq-id="333" status="0" rank="6" chain-id="333"/>
  <Object id="middle"    id-parent="top"    uniq-id="020" status="0" rank="3" chain-id="333"/>
  <Object id="top"                          uniq-id="001" status="0" rank="1" chain-id="333"/>

  <Object id="bottom-6"  id-parent="middle" uniq-id="666" status="0" rank="7" chain-id="666"/>
  <Object id="middle"    id-parent="top"    uniq-id="020" status="0" rank="3" chain-id="666"/>
  <Object id="top"                          uniq-id="001" status="0" rank="1" chain-id="666"/>

  <Object id="bottom-9"  id-parent="middle" uniq-id="999" status="0" rank="6" chain-id="999"/>
  <Object id="middle"    id-parent="top"    uniq-id="020" status="0" rank="3" chain-id="999"/>
  <Object id="top"                          uniq-id="001" status="0" rank="1" chain-id="999"/>
</root>

Приветствую всех ваших решений, как улучшить XSLT-код

1 Ответ

1 голос
/ 31 января 2020

Всегда трудно реконструировать ваши требования из нерабочего кода, но я думаю, что вы пытаетесь выбрать элементы с @status="0", и для каждого из них вывести на экран логических предков, то есть рекурсивное расширение отношения parent(X), где parent(X) выбирает элемент, @id которого равен X/@parent-id.

Я давно не кодировал в XSLT 1.0 (он был заменен на долгое время время сейчас ...) поэтому извиняюсь, если я сделаю какие-либо ошибки.

Сначала определите ключ, который выбирает объекты по id:

<xsl:key name="by-id" match="Object" use="@id"/>

Теперь определите рекурсивный шаблон для печати логических предков узел:

<xsl:template match="Object" mode="ancestors">
  <xsl:copy-of select="."/>
  <xsl:apply-templates select="key('by-id', @parent-id)" mode="ancestors"/>
</xsl:template>

и теперь вызывайте его для выбранных элементов:

<xsl:template match="/">
 <root>
  <xsl:apply-templates select="root/Object[@status='0']" mode="ancestors"/>
 </root>
</xsl:template>

Не проверено.

...