[Bug 9722] [XSLT 2.1] Enhancement to conditional modes

http://www.w3.org/Bugs/Public/show_bug.cgi?id=9722





--- Comment #3 from Evan Lenz <evan@evanlenz.net>  2010-05-12 21:44:28 ---
Dynamic access to mode names would give me a really ugly way to do what I
want... (see Example #2 below). But I think it would be so painful as to defeat
the purpose for me (especially since I can already pass a "mode name" via a
tunnel parameter at the original point of invocation).

What I'd really like to do is refer to the *previous* mode, both in
apply-templates and in match patterns.

So <xsl:apply-templates/> would now allow mode="#previous"

And <xsl:template> would now allow mode="myPreviousMode/myCurrentMode" -
limited to one separator ("/" as here or some other non-space, non-QName
character).

Thus every invocation of apply-templates is conceptually a conditional mode
invocation, parameterized by the current mode at the point of invocation. I can
think of several ways of modeling this (e.g., a mode can actually be a *pair*
of QNames, depending on whether its previous mode is ever referenced in the
stylesheet).



EXAMPLE #1 (with access to previous mode):

<!-- In stage 1, delete <foo>'s content -->
<xsl:template mode="stage1/content" match="foo"/>

<!-- In stage 3, add <bar/> after <bat/> -->
<xsl:template mode="stage3/after" match="bat">
  <bar/>
</xsl:template>


<!-- The boilerplate code that enables me to write the above surgically precise
rules -->
<!-- By default, copy everything unchanged -->
<xsl:template mode="stage1
                    stage2
                    stage3" match="*">
  <xsl:apply-templates mode="before" select="."/>
  <xsl:copy>
    <xsl:apply-templates mode="#current" select="@*"/>
    <xsl:apply-templates mode="content" select="."/>
  </xsl:copy>
  <xsl:apply-templates mode="after" select="."/>
</xsl:template>

<!-- By default, process children -->
<xsl:template mode="content" match="*">
  <xsl:apply-templates mode="#previous"/>
  <!-- Processor knows statically that this will be either "stage1", "stage2",
or "stage3" -->
</xsl:template>

<!-- By default, don't add anything before or after -->
<xsl:template mode="before
                    after" match="*"/>



EXAMPLE #2 (achieving the same, using only current-mode()):

<!-- In stage 1, delete <foo>'s content -->
<xsl:template mode="stage1-content" match="foo"/>

<!-- In stage 3, add <bar/> after <bat/> -->
<xsl:template mode="stage3-after" match="bat">
  <bar/>
</xsl:template>


<!-- The boilerplate code that enables me to write the above surgically precise
rules -->
<!-- By default, copy everything unchanged -->
<xsl:template mode="stage1
                    stage2
                    stage3" match="*">
  <xsl:variable name="stage1" select="current-mode() eq 'stage1'"/>
  <xsl:variable name="stage2" select="current-mode() eq 'stage2'"/>
  <xsl:choose>
    <xsl:when test="$stage1">
      <xsl:apply-templates mode="stage1-before" select="."/>
    </xsl:when>
    <xsl:when test="$stage2">
      <xsl:apply-templates mode="stage2-before" select="."/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates mode="stage3-before" select="."/>
    </xsl:otherwise>
  </xsl:choose>
  <xsl:copy>
    <xsl:apply-templates mode="#current" select="@*"/>
    <xsl:choose>
      <xsl:when test="$stage1">
        <xsl:apply-templates mode="stage1-content" select="."/>
      </xsl:when>
      <xsl:when test="$stage2">
        <xsl:apply-templates mode="stage2-content" select="."/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates mode="stage3-content" select="."/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:copy>
  <xsl:choose>
    <xsl:when test="$stage1">
      <xsl:apply-templates mode="stage1-after" select="."/>
    </xsl:when>
    <xsl:when test="$stage2">
      <xsl:apply-templates mode="stage2-after" select="."/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates mode="stage3-after" select="."/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- By default, process children -->
<xsl:template mode="stage1-content
                    stage2-content
                    stage3-content" match="*">
  <xsl:choose>
    <xsl:when test="current-mode() eq 'stage1-content'">
      <xsl:apply-templates mode="stage1"/>
    </xsl:when>
    <xsl:when test="current-mode() eq 'stage2-content'">
      <xsl:apply-templates mode="stage2"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:apply-templates mode="stage3"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- By default, don't add anything before or after -->
<xsl:template mode="stage1-before
                    stage2-before
                    stage3-before
                    stage1-after
                    stage2-after
                    stage3-after" match="*"/>


Another way to look at this is that I want my XSLT processor to do the work of
automatically translating Example #1 into Example #2 for me, just as it already
does with mode="#current".

-- 
Configure bugmail: http://www.w3.org/Bugs/Public/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.

Received on Wednesday, 12 May 2010 21:44:30 UTC