标记树中的叶节点 (XSLT 1.0)

labeling leaf nodes in tree (XSLT 1.0)

我有一个xml,我想处理,然后简单地依次标记每个叶节点,翻转或翻转,除非满足某些条件。

以这个为例xml

<root>
   <tx>
      <alloc>
         <event>a</event>
         <event>b</event>
      </alloc>
      <alloc>
         <event>c</event>
         <event>d</event>
         <event>d1</event>
      </alloc>
   </tx>
   <tx>
      <alloc>
         <event>e</event>
         <event>f</event>
         <event>g</event>
      </alloc>
   </tx>
</root> 

假设我们想要标记每个事件节点,翻转然后翻转然后翻转,等等除非事件是“e”

请注意,事件的标签独立于层次结构。

所以...

<root>
   <tx>
      <alloc>
         <event flip="true">a</event>
         <event flip="false">b</event>
      </alloc>
      <alloc>
         <event flip="true">c</event>
         <event flip="false">d</event>
         <event flip="true">d1</event>
      </alloc>
   </tx>
   <tx>
      <alloc>
         <event flip="true">e</event>
         <event flip="false">f</event>
         <event flip="true">g</event>
      </alloc>
   </tx>
</root>

所以根据我们的规则,节点“d1”为“真”且“e”在继续之前保持为“真”。

现在...我可以找到一种方法来做到这一点,但感觉它不太适合 XSLT。

如果我用某种函数式语言来做这件事,我会递归处理树,基本上是克隆它,通过每个递归函数传递 flip/flop 的值,所以像...

所以例如 tx 处理模板看起来像这样(这是编造的)

   <xsl:template match="tx" mode="label">
      <xsl:param name="flip_flip"/>
      <xsl:variable name="allocations">
         <xsl:apply-templates select="alloc" mode="label">
            <xsl:with-param name="flip_flip" select="$flip_flop"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:copy-of select="$allocations"/>
      <xsl:variable name="new_flip_flip" select="alloc/event/@flip[last()]"
      <xsl:apply-templates select="following-sibling::tx[1]" mode="label">
         <xsl:with-param name="flip_flip" select="$new_flip_flip + 1"/>
      </xsl:apply-templates>
   </xsl:template>

即依次处理每个元素,拉出上次计算的触发器值,然后处理下一个。

感觉xslt很丑

另一种选择是计算前面发生的事件的数量,减去异常的数量,然后计算出 mod 2 flip 是真还是假。 再次,感觉笨重,计算量大。

这样的东西对你有用吗:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="event">
    <xsl:variable name="i">
        <xsl:number count="event[not(.='e')]" level="any" />
    </xsl:variable>
    <event flip="{boolean($i mod 2)}">
        <xsl:apply-templates/>
    </event>
</xsl:template>

</xsl:stylesheet>