tags:

views:

882

answers:

3

Hi, I am serching an XPath function that works like the XPath 2.0 fn:max function. A function that returns the maximum of several parameters.

After searching a lot I figured out this way:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:math="http://exslt.org/math" 
xmlns:exslt="http://exslt.org/common" 
xmlns:func="http://exslt.org/functions"
xmlns:my="http://myns.com"
extension-element-prefixes="math exslt func">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
     <root>
      <xsl:value-of select="my:max(1,2)"/>
     </root>
    </xsl:template>


    <func:function name="my:max">
     <xsl:param name="e1"/>
     <xsl:param name="e2"/>

     <xsl:variable name="x">
      <val><xsl:value-of select="$e1"/></val>
      <val><xsl:value-of select="$e2"/></val>
     </xsl:variable>

     <func:result select="math:max(exslt:node-set($x)/val)"/>
    </func:function>
</xsl:stylesheet>

Is it possible to do it so that my max function can take more elements?

Cheers
Jan

A: 

Presumably you could specify the xml (for the node-set) as the input argument?

I'm not "up" on exslt, but using msxsl (just for the node-set function, which is also in exslt):

  <xsl:template name="max">
    <xsl:param name="values"/>
    <xsl:for-each select="msxsl:node-set($values)/val">
      <xsl:sort data-type="number" order="descending"/>
      <xsl:if test="position()=1">
        <xsl:value-of select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
  ...
  <xsl:call-template name="max">
    <xsl:with-param name="values">
      <val>13</val>
      <val>123</val>
      <val>18</val>
    </xsl:with-param>
  </xsl:call-template>
Marc Gravell
MS-XSL seems the completely wrong direction to me.
Nerdling
msxsl:node-set was **purely** because that is the IDE I have to hand; as I believe I mentioned, exslt:node-set should do just as well. I simply can't test with exslt, and I'd rather post a tested answer.
Marc Gravell
+1  A: 

I don't have my XSLT 1.0 book in front of me, but I think the key here is that you can select 'node sets' and set those equal to your parameter variable, rather than having one-node-per-parameter. Here's a rough guess:

<xsl:template match="/">
    <root>
      <xsl:call-template name="max">
        <xsl:with-param name="values">
          <val>1</val>
          <val>2</val>
          <val>3</val>
        </xsl:with-param>
      </xsl:call-template>
    </root>
</xsl:template>


<func:function name="my:max">
    <xsl:param name="x"/>

    <func:result select="math:max($x/val/*)"/>
</func:function>

edit: re-read the question along with some XSLT 1.0 guidance. It should resemble the other answer, simplified only slightly. Keep in mind that if the numbers you want come from the XML data, you can use the select= attribute on xsl:with-param to automatically select the nodes you want to compare.

Jweede
A: 

Thank you for your ideas.

You helped me to understand everything a bit better. But my original intention was to get a handy XPath function that works on xsl variables.

<!-- works with XPath 2.0 -->
<xst:template match="img/@height">
  <xsl:variable name="$maximageheight" select="200">
  <xsl:value-of select="fn:max( $maximageheight , . )"/>
</xsl:template>

<!-- until now the only way I see to do the same in XSL 1.0 -->
<xst:template match="img/@height">
<xsl:variable name="$maximageheight" select="200">
  <xsl:call-template name="max">
    <xsl:with-param name="values">
      <val>$maximageheight</val>
      <val><xsl:value-of select="."/></val>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>

For a fixed umber of parameters it would be possible to implement an exslt function:

<func:function name="my:max" xmlns:func="http://exslt.org/functions"&gt;
  <xsl:param name="e1"/>
  <xsl:param name="e2"/>

  <xsl:variable name="x">
    <val><xsl:value-of select="$e1"/></val>
    <val><xsl:value-of select="$e2"/></val>
  </xsl:variable>

  <func:result select="math:max(exslt:node-set($x)/val)"/>
</func:function>

But i do not see a way to implement it vor a variable number of parameters.

Then maybe it can't be done... btw, this would be better as an update to the question, rather than an answer.
Marc Gravell