Re: [xsl] newbie : search an attribute's item

Subject: Re: [xsl] newbie : search an attribute's item
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 23 Nov 2001 17:29:42 +0000
Hi Laurent,

> What do I have to write in my paragraph's rule to be able to set the
> line-height of fo:block to the max ot attributes value of font-size
> + 2 ?

You can find the maximum value of a set of nodes in a number of ways.
You're fortunate in that the values that you've got held in the value
attributes are exactly the values that you want to find the maximum
value of, so you have a good range of options.

The set of nodes that you want to get the maximum of seems to be the
value attributes of the descendant font-size elements of the current
paragraph, which you can collect together using the location path:

  .//font-size/@value

Assume that this node set is assigned to the $values variable.
  
First and easiest, you could use an extension function to get the
maximum of the set of nodes. Saxon, 4XSLT, jd.xslt and libxslt all
support math:max() in the namespace http://exslt.org/math to do this,
or you could use xalan:max() in the namespace
http://xml.apache.org/xslt if you're using Xalan. Then you just need
to do:

  <fo:block line-height="{math:max($values) + 2}">
    ...
  </fo:block>

Alternatively, you could use a simple XPath to get the maximum - find
the first value within the list for which there is no greater value in
the list:

  <fo:block line-height="{$values[not($values > .)][1] + 2}">
    ...
  </fo:block>

Or you could iterate over the values in descending numeric order and
pick out the first one (the largest):

  <xsl:variable name="maxFontSize">
    <xsl:for-each select="$values">
      <xsl:sort select="." data-type="number" order="descending" />
      <xsl:if test="position() = 1">
        <xsl:value-of select="." />
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>
  <fo:block line-height="{$maxFontSize + 2}">
    ...
  </fo:block>

Or you could create your own recursive template to work out the
maximum:

<xsl:template name="maximum">
  <xsl:param name="nodes" select="/.." />
  <xsl:param name="maximum" select="$nodes[1]" />
  <xsl:choose>
    <xsl:when test="$nodes">
      <xsl:call-template name="maximum">
        <xsl:with-param name="nodes"
                        select="$nodes[position() > 1]" />
        <xsl:with-param name="maximum">
          <xsl:choose>
            <xsl:when test="$nodes[1] > $maximum">
              <xsl:value-of select="$nodes[1]" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$maximum" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$maximum" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

And use it as follows:


  <xsl:variable name="maxFontSize">
    <xsl:call-template name="maximum">
      <xsl:with-param name="nodes" select="$values" />
    </xsl:call-template>
  </xsl:variable>
  <fo:block line-height="{$maxFontSize + 2}">
    ...
  </fo:block>
  
Or you could use one of Dimitre's generic templates to do the job for
you and call it similarly.

The templates and the built-in extension functions are likely to give
you the best performance if you have a large number of font-size
elements within your paragraphs; otherwise one of the simpler methods
will do the job just as well, most likely.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread