tags:

views:

695

answers:

3

How can find max of three numbers in XSL ? More Information : I have three numbers say 1.0, 2.0, 5.0....I don't have any nodes set... I would like to find maximum of 1.0, 2.0 and 5.0.....

Example :

AIM : TO know which type of node <MYNODE>, <DOC>, <PIC> 
is having maximum count and whant's the count number ?

    <ROOT>
              <MYNODES>
                   <MYNODE>A</MYNODE>
                   <MYNODE>B</MYNODE>
                   <MYNODE>C</MYNODE>
                   <MYNODE>D</MYNODE>
              </MYNODES> 
              <DOCS>
                   <DOC>1</DOC>
                   <DOC>2</DOC>
                   <DOC>3</DOC>
              </DOC> 
              <PICS>
                   <PIC>a.jpeg</PIC>
                   <PIC>b.jpeg</PIC>
                   <PIC>c.jpeg</PIC>
                   <PIC>d.jpeg</PIC>
                   <PIC>e.jpeg</PIC>
              </PICS> 
    </ROOT>
A: 

5.0 is the largest of the three numbers. Hardcode it and be done with it. :-)

Seriously though, you may wish to take another path. Logic like this is trivial in other languages, but can be a pain in XSLT. You should consider writing a simple extension for the XSLT engine rather than messing around trying to make XSLT do what you want it to.

Peter Dolberg
Hi Peter,I am new to XSL....Can you please help me in extension...Any links or pointers would be useful
+1 for making me laugh!
Cerebrus
Writing an XSLT extension must be done differently depending on which XSLT implementation you're using. Which one are you using? Xalan in Java, Xalan in C++, Saxon, MSXML, Firefox?
Peter Dolberg
+1  A: 

With your input XML, you would find the maximum count you are looking for like this:

<xsl:variable name="vMaxChildren">
  <xsl:for-each select="/ROOT/*">
    <xsl:sort select="count(*)" data-type="number" order="descending" />
    <xsl:if test="position() = 1">
      <xsl:value-of select="concat(name(), ': ', count(*))" />
    </xsl:if>
  </xsl:for-each>
</xsl:variable>

<xsl:value-of select="$vMaxChildren" />

Which would produce:

PICS: 5
Tomalak
Up-voted as completely correct. See my comment-answer to your comment to my answer. :)
Dimitre Novatchev
+1  A: 

This question is incorrectly formulated and the provided "XML document' is not well-formed!

Do note that it is generally meaningless to ask about the maximum of a set of numbers. There can be more than one number with the highest value. Therefore, the solutions below show just the first item with the maximum value.

This is one possible XSLT 1.0 solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output method="text"/>

    <xsl:template match="/">
      <xsl:variable name="vNameMaxCount">
       <xsl:for-each select="*/*">
         <xsl:sort select="count(*)" data-type="number"
          order="descending"/>

          <xsl:if test="position() = 1">
             <xsl:value-of select="concat(name(),'+', count(*))"/>
          </xsl:if>
       </xsl:for-each>
      </xsl:variable>

      One element with maximum children is: <xsl:text/>
      <xsl:value-of select="substring-before($vNameMaxCount, '+')"/>

      Maximum number of children: <xsl:text/>
      <xsl:value-of select="substring-after($vNameMaxCount, '+')"/>

    </xsl:template>
</xsl:stylesheet>

when the above transformation is applied on the following XML document (produced from the one provided after spending 10 minutes to make it well-formed!):

<ROOT>
    <MYNODES>
     <MYNODE>A</MYNODE>
     <MYNODE>B</MYNODE>
     <MYNODE>C</MYNODE>
     <MYNODE>D</MYNODE>
    </MYNODES>
    <DOCS>
     <DOC>1</DOC>
     <DOC>2</DOC>
     <DOC>3</DOC>
    </DOCS>
    <PICS>
     <PIC>a.jpeg</PIC>
     <PIC>b.jpeg</PIC>
     <PIC>c.jpeg</PIC>
     <PIC>d.jpeg</PIC>
     <PIC>e.jpeg</PIC>
    </PICS>
</ROOT>

the wanted result is produced

  One element with maximum children is: PICS

  Maximum number of children: 5

An XSLT 2.0 solution (actually just an XPath 2.0 soulution):

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 >
 <xsl:output method="text"/>

 <xsl:template match="/">
   <xsl:sequence select=
    "for $vmaxChildrein in max(/*/*/count(*)),
         $vmaxNode in */*[count(*) = $vmaxChildrein][1]
      return 
         (name($vmaxNode), 
          'has the max no of children:', 
          $vmaxChildrein
          )
    "/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the above document, the wanted result is produced:

PICS has the max no of children: 5

For finding the maximum of more tricky properties that cannot be immediately expressed as an XPath expression and used in <xsl:sort>, do use the f:maximum() function of FXSL.

Dimitre Novatchev
Will this find the maximum number of children or siblings a node has?
TStamper
@TStamper The two solutions presented *do* find the maximum number of children elements. Don't you see it yourself?
Dimitre Novatchev
+1 for pointing out that is *one* node (not *the* node) with the maximum count of children. Other than that is is equal to my solution.
Tomalak
@Tomalak Fully agreed and thanks for your appreciation! This said, I also point out people to FXSL, which they can conveniently use in case it is difficult or impossible to provide a "ranking function" as a single XPath expression. Also, I have provided an XPath 2.0 solution, which adds additional information forthose, who need it. And all of us need now more than ever information that would ease our complete transition into XPath 2.0/XSLT 2.0. I am upvoting your answer as completely correct.
Dimitre Novatchev
XPath 2.0 is pretty amazing, I must say.
Tomalak