Caroline
Caroline

Reputation: 171

xslt 3.0 parameters not being overwritten

Given:

<table>
  <title>Inspection</title>
  <tgroup/>
     <tbody>
       <row>
       <entry>
          <para>Blend well.</para>
       </entry>
       </row>
       <row>
           <entry>
              <effect effrg="cde"/>
           </entry>
        </row>
        <!-- this entry would be empty -->
       <row>
           <entry>
              <effect effrg="cde"/>
           </entry>
        </row>
       <row>
           <entry>
           <!-- first effect would create a block, second should be ignored -->
              <effect effrg="abc"/>
              <effect effrg="abc"/>
           </entry>
        </row>
    </tbody>
</table>

I was trying to prevent an error caused by an empty fo:table-cell. This could happen when the only child of <entry> was <effect>, and that effect/@effrg matched the previous @effrg, because then nothing would be printed. I wanted to minimize extraneous fo:blocks so I thought I could use parameters as a flag:

<xsl:template match="entry/effect[not(*)]" priority="50"> 
    <xsl:param name="need-block" as="xs:boolean" select="true()"/>
    
    <xsl:variable name="preceding-effrg" as="xs:string?">
        <xsl:call-template name="get-previous-effectivity"/>
    </xsl:variable>
    
    <xsl:variable name="effrg" as="xs:string?" select="normalize-space(@effrg)"/>
           
    <xsl:choose>
        <xsl:when test="$effrg ne $preceding-effrg">
            <fo:block xsl:use-attribute-sets="effect">
                <xsl:text>{$asterisks3} </xsl:text>
                <xsl:apply-templates select="@effrg"/>
            </fo:block>
            <xsl:apply-templates>
                <xsl:with-param name="need-block"  as="xs:boolean" select="false()" tunnel="true"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:when test="$need-block="false()"/>
        <!-- any other sibling elements will create a block -->
        <xsl:when test="../*[local-name() ne 'effect']"/>
        <xsl:when test="following-sibling::*"/> 
        <xsl:otherwise>
            <fo:block/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="get-previous-effectivity">
        <xsl:param name="pos" as="xs:integer" select="1" />
        <xsl:value-of select="preceding::effect[$pos]/@effrg[normalize-space(.) != ''][1]"/>
    </xsl:template>

I couldn't change the value of $need-block in the effect template by passing it another value. If a default value was assigned it retained that value, and if it didn't have a default value, it remained empty, even though I confirmed the parameter passing in was false(). I tried tunneling, turning off tunneling, passing it from the parent and passing from a template where $need-block was defaulted to false(). When I stepped through the code it seemed to ignore the $with-param. I've done this in xslt 1.0, is that considered bad practice?

Upvotes: 0

Views: 75

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167716

I wonder whether you can't simply use an accumulator e.g.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:mode use-accumulators="#all"/>
  
  <xsl:param name="asterisks3" as="xs:string">***</xsl:param>

  <xsl:accumulator name="last-effrg" as="xs:string?" initial-value="()">
    <xsl:accumulator-rule phase="end" match="effect[@effrg]" select="normalize-space(@effrg)"/>
  </xsl:accumulator>

  <xsl:template match="entry/effect[not(*)][not(normalize-space(@effrg) = accumulator-before('last-effrg'))]"> 
      <fo:block>
        <xsl:text>{$asterisks3} </xsl:text>
        <xsl:apply-templates select="@effrg"/>
      </fo:block>
  </xsl:template>  
  
</xsl:stylesheet>

will output two

<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">*** cde</fo:block>
..
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">*** abc</fo:block>

I think your parameter passing fails as you neeed the parameter value in siblings, not in children or descendants.

Upvotes: 0

Michael Kay
Michael Kay

Reputation: 163625

If you declare it as a tunnel parameter in xsl:with-param then it will only match a parameter declared with tunnel="yes" in xsl:param, and vice versa.

Upvotes: 1

Related Questions