RE: [xsl] selecting node with longest data string

Subject: RE: [xsl] selecting node with longest data string
From: "Sullivan, Dan" <dsullivan@xxxxxxxxxxx>
Date: Sat, 25 Aug 2001 07:59:16 -0700
Here are two ways to find the item's with the longest text content.

This first solution is using the same technique as you, but eliminates
building the string and pulling it apart (watch for line breaks)

The second solution is a bit more typing but eliminates sorting the
input, so should be faster. (watch for line breaks)

Note that in both solutions a key is used to pull out all of the longest
item's, if there is more than one. If you only want a single longest
item this could be eliminated. Of course there can't be two longest but
you know what I mean.:)

Dan

First solution:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <!-- used later to find all item's as long as the longest single item
found -->
  <xsl:key name="length" match="/items/item" use="string-length(.)"/>

  <xsl:template match="/">
    <longest>
      <!-- iterate through items in order of length, longest first -->
      <xsl:for-each select="items/item">
        <xsl:sort select="string-length(.)" data-type="number"
order="descending"/>
        <!-- only use the first on found -->
        <xsl:if test="position()=1">
          <!-- copy out all of the items as long as this first one -->
          <xsl:copy-of select="key('length', string-length(.))"/>
        </xsl:if>
      </xsl:for-each>
    </longest>
  </xsl:template>
</xsl:stylesheet>

Second solution

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="1.0">
  <!-- just to make output easy to read -->
  <xsl:output method="xml" indent="yes"/>
  <!-- used at end to find all item's that have the same length
       as longest one found
-->
  <xsl:key name="length" match="/items/item" use="string-length(.)"/>
  <!-- keeps iterating through every item to find the longest one -->
  <xsl:template name="find-longest">
    <!-- item currently being looked at -->
    <xsl:param name="item"/>
    <!-- longest one found so far -->
    <xsl:param name="longest"/>
    <!-- This is the next item to be looked at -->
    <xsl:variable name="next"
select="$item/following-sibling::item[1]"/>
    <xsl:choose>
      <xsl:when test="$next">
      <!-- if there are more items keep looking -->
        <xsl:call-template name="find-longest">
          <!-- pass in the next item to be tested -->
          <xsl:with-param name="item" select="$next"/>
          <!-- pass in the current item as the longest if it is longer
than the next one -->
          <xsl:with-param name="longest"
select="$item[string-length(.)>=string-length($longest)]|$longest[not(st
ring-length($item) >= string-length(.))]"/>
          </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <!-- nothing else to look at, $longest does have the longest now
-->
        <xsl:value-of select="$longest"/>
      </xsl:otherwise>
  </xsl:choose>
  </xsl:template>

  <xsl:template match="/">
    <!-- wrapper to make output well-formed -->
    <longest>
      <!-- holds longest item -->
      <xsl:variable name="longest">
        <!-- start looking for longest by passing inline="
             the first item as the longest -->
      <xsl:call-template name="find-longest">
        <xsl:with-param name="item" select="/items/item[1]"/>
        <xsl:with-param name="longest" select="/items/item[1]"/>
      </xsl:call-template>
    </xsl:variable>
    <!-- since find-longest only finds one longest, use key to find all
of them -->
    <xsl:copy-of select="key('length', string-length($longest))"/>
    </longest>
  </xsl:template>
</xsl:stylesheet>


-----Original Message-----
From: Mayura Malagala [mailto:TS2664@xxxxxxxxxxxx]
Sent: Saturday, August 25, 2001 7:17 AM
To: 'xsl-list@xxxxxxxxxxxxxxxxxxxxxx'
Subject: [xsl] selecting node with longest data string


Hi All,

I'm using MSXML3 sp1.

I've got an XML that looks like :

<?xml version="1.0" encoding="ISO8859-1"?>
<items>
	<item>dd</item>
	<item>eeeee</item>
	<item>aaa</item>
	<item>ffffffffff</item>
	<item>c</item>
	<item>bbbb</item>
</items>

I want to get the item which has the longest data string as its value.
I managed to do it with the following xsl, but it seems very crude.
Could
someone please tell me a more efficient way of doing this.


<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.
0" >
<xsl:output method='html' />

<xsl:template match="/">
	<xsl:variable name="SortedItems" >
		<xsl:call-template name="SortItems" />
	</xsl:variable>
	
	<xsl:variable name="FinalValue">
		<xsl:value-of select="substring-before($SortedItems,'|')
" />
	</xsl:variable>
	
	longest = <xsl:value-of select="string-length($FinalValue)" />
	
</xsl:template>


<xsl:template name="SortItems">
	<xsl:for-each select="items/item">
		<xsl:sort select="string-length(.)" data-type="number"
order="descending" />
		<xsl:value-of select="." />|
	</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Thanks in advance,
Mayura

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


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


Current Thread