XSLT:如何处理命名的兄弟姐妹和跳跃'事后超越他们?

时间:2013-11-30 11:58:07

标签: xml xslt

在这个xml中:

<root>
 <a/>
 <b/>
 <c/>
 <x/>
 <b/>
 <c/>
 <a/>
</root>

我希望在a之后的任何组合中添加任何a和任何b或c的属性,直到达到某个其他元素,如下所示:

<root>
  <a myattr='yes'/>
  <b myattr='yes'/>
  <c myattr='yes'/>
  <x/>
  <b/>
  <c/>
  <a myattr='yes'/>
</root>

请注意,忽略前面a的b或c。 我想要的是处理a,然后在它的模板中执行for-each -sibling :: b或c并处理它们,但是我如何“抛出”处理超出这些元素以便处理开始(在这个例子)在x?

这可能吗?

3 个答案:

答案 0 :(得分:1)

以下XSLT样式表应生成所需的输出。

在匹配bc元素时,会查找前一个a和“ab以及{{1}以外的任何内容“兄弟姐妹并比较他们的立场。如果c兄弟是最近的,那么它会添加属性。

a

答案 1 :(得分:0)

你可以通过“一次一个兄弟”尾递归来做到这一点。从你之前的问题我收集到你正在使用XSLT 2.0,所以你可以使用下一个匹配非常优雅地做到这一点

<xsl:template match="root">
  <xsl:copy><xsl:apply-templates select="*[1]" /></xsl:copy>
</xsl:template>

<xsl:template match="a">
  <xsl:param name="inGroup"/>
  <xsl:next-match>
    <!-- a is always in a group -->
    <xsl:with-param name="inGroup" select="true()" />
  </xsl:next-match>
</xsl:template>

<xsl:template match="*[not(self::a | self::b | self::c)]">
  <xsl:param name="inGroup"/>
  <xsl:next-match>
    <!-- anything other than a, b, c is never in a group -->
    <xsl:with-param name="inGroup" select="false()" />
  </xsl:next-match>
</xsl:template>

<!-- b and c will match this directly, and take their "groupiness" from the
     previous iteration -->
<xsl:template match="*">
  <xsl:param name="inGroup"/>
  <xsl:copy>
    <xsl:copy-of select="@*" />
    <xsl:if test="$inGroup">
      <xsl:attribute name="myattr">yes</xsl:attribute>
    </xsl:if>
    <xsl:copy-of select="node()" />
  </xsl:copy>
  <!-- process the next sibling, passing on the group flag -->
  <xsl:apply-templates select="following-sibling::*[1]">
    <xsl:with-param name="inGroup" select="$inGroup" />
  </xsl:apply-templates>
</xsl:template>

相同的代码应该在1.0中有效,除非您需要为*模板name以及match提供,然后使用call-template代替{{ 1}}。

答案 2 :(得分:-1)

我想在XSLT 1.0中尝试这个:

...
<xsl:template match="a">
    <xsl:copy>
        <xsl:attribute name="myattr">yes</xsl:attribute>
    </xsl:copy>
</xsl:template>

<xsl:template match="b|c">
    <xsl:copy>
        <xsl:variable name="lineage">
            <xsl:call-template name="lineage"/>
        </xsl:variable>

        <xsl:if test="$lineage = 'true'">
            <xsl:attribute name="myattr">yes</xsl:attribute>
        </xsl:if>
    </xsl:copy>
</xsl:template>

<xsl:template match="*">
    <xsl:copy/>
</xsl:template>

<xsl:template name="lineage">
<xsl:param name="i" select="1"/>
<xsl:choose>
    <xsl:when test="$i > count(preceding-sibling::*)"/>

    <xsl:when test="name(preceding-sibling::*[$i])='a'">
        <xsl:value-of select="true()"/>
    </xsl:when>

    <xsl:when test="name(preceding-sibling::*[$i])='b' 
                    or 
                    name(preceding-sibling::*[$i])='c'">
        <xsl:call-template name="lineage">
            <xsl:with-param name="i" select="$i+1"/>
        </xsl:call-template>
    </xsl:when>
</xsl:choose>
</xsl:template>