【问题标题】:Get a common id to all ancestors from the lowest member从最低成员中获取所有祖先的共同 id
【发布时间】:2020-01-31 10:20:26
【问题描述】:

尝试组装正确的 XSLT 代码以将公共 ID 分配给上述所有元素,该 ID 取自递归链的最低成员(来自其“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 代码的所有解决方案

【问题讨论】:

  • 我不得不承认我已经多次阅读了您的描述,并查看了输入和假定的输出 xml,但我不明白您要做什么,我的意思是我理解您正在尝试从输入中获取假定的输出,但我不了解假定输出中的元素如何相互关联的逻辑。希望您能澄清这个问题,以防其他人有同样的问题。
  • /@*[last()] 没有任何意义。您要求的是最后一个属性,但属性的顺序是完全不可预测的。
  • to user254694 - 这个描述可能与前面的类似,但这个问题非常具体和新颖。它还依赖于源 XML,即递归(是的,递归的存在将我最近的所有问题结合在一起。这件事不是最简单的,所以我必须修改它)。顺便说一句,在我认为的所有内容中 - 这个对主要条件\问题非常清楚('从最低成员那里获得所有祖先的共同 id')。换个说法?我会试试的。
  • 所有之前的请求,一般来说,都针对一个方向 - 解开整个互连元素链,恢复它们并以某种方式明确它们在人类逻辑和感知中的可读性。
  • 如果我们继续用人类逻辑(空间和时间)来描述——当前问题实际上是之前递归算法保留的地方的延续。 1- step - 我们找到递归链的“末端”。 2 - 现在你需要“遍历”这条链,现在知道“较低”元素的 uniq-id 值 - 以相反的顺序(从下到上)将其值分配给所有元素(至少现在我认为可能的算法的抽象逻辑就是这样。战术问题是要知道如何在特定的 xslt 代码中表示这种抽象。

标签: xml xslt xslt-1.0


【解决方案1】:

从非工作代码逆向工程你的需求总是很困难,但我认为你要做的是选择带有@status="0"的元素,并为每个元素显示逻辑祖先,即关系parent(X)的递归展开,其中parent(X)选择@id等于X/@parent-id的元素。

自从我在 XSLT 1.0 中编码以来已经有很长一段时间了(现在它已经被取代了很长时间......)所以如果我犯了任何错误,我们深表歉意。

首先定义一个通过id选择对象的key:

<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>

未测试。

【讨论】:

  • 谢谢迈克尔!我会尽快实施。
  • 决定制作一个仅依赖您的代码的新程序集。该算法确实根据 status = "0" 确定了链的“最低”元素,但并没有走得更远(实际上,本集真正的 MacGuffin 是什么)。 xsltfiddle.liberty-development.net/pPJ9hEf
  • 这次我要实现的主要目标不是解释从上到下的方向组装的链条,而是现在以相反的顺序重新组装,其中每个父元素 a) 重复 b) (主要选项!) - 获得一个新的公共属性“chain-id”,其值将取自“下层元素”的“uniq-id”(这里它们表示为“333”、“666”、“999”值)互连方案(基本)imgur.com/p868Xqc互连输出方案imgur.com/PRDYvyo
  • 从使用 XSLT 的一点经验来看,我可以假设解决方案是使用 XSLT 词法,例如“位置”和“最后”。粗略地说,当 Object 元素的 'position' 为 'last' 时,开始发生反向重建及其解释。
  • 我查看了诸如 Novachev 的方法 stackoverflow.com/questions/58101443/… 之类的资源,但是虽然这些知识提供了如此多的乐高积木,以至于即使了解应该发生的事情的形式逻辑,我也无法弄清楚如何使其发挥作用代码。
猜你喜欢
  • 1970-01-01
  • 2014-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
相关资源
最近更新 更多