Solved

XSL max/string compare

Posted on 2009-07-14
10
1,137 Views
Last Modified: 2013-11-18
So I've got a SharePoint list of items, some of which have a Comment and all of which are associated with a Step.
The Step field is essentially a lookup on another table's column which incorporates the sort value followed by the step name.

I need to pull only the valid Comment associated with the highest sort value embedded in the Step

Problem is that the comments are not always present, and the steps are not always in the same order as the IDs, so position() is out.

My last attempt with a xsl:sort is in the CODE section below.  The substring-before(substring-after( part filters out empty comments (<div></div>)

Any Ideas?
<xsl:for-each select="$Dates[substring-before(substring-after(@Comment,'&gt;'),'&lt;') !=''][1]">
	<xsl:sort select=. data-type="text" order=descending/>
	<xsl:value-of select="substring-before(substring-after(@Comment,'&gt;'),'&lt;')"/>
</xsl:for-each>

Open in new window

0
Comment
Question by:RobertNoble
  • 6
  • 4
10 Comments
 
LVL 11

Assisted Solution

by:andrei_teodorescu
andrei_teodorescu earned 120 total points
ID: 24859447
Please provide more code and also a simple representation of your data
And what do you intend with select="$Dates[substring-before(substring-after(@Comment,'>'),'<') !=''][1]"

if you want to test for a variable if is empty or not, in your case:
<xsl:if test="substring-before(substring-after(@Comment,'>'),'<')">
0
 

Author Comment

by:RobertNoble
ID: 24860148
Below is what the code looks like now.  It's functional, but pulls up ALL comments instead of only the most 'recent' one.

You're right, the != '' at the end of the test and for-each can be dropped without affecting the outcome.

If i'm not mistaken, the XSLT receives the data from 3 sharepoint lists in the following (abbreviated) forma, where the 3rd references the other 2t:

<Packages>
      <Rows>
            <Row>
                  <Package>
                        <PackageName>A</PackageName>
                  </Package>
                  <Package>
                        <PackageName>B</PackageName>
                  </Package>
                  <Package>
                        <PackageName>C</PackageName>
                  </Package>
            </Row>
      </Rows>
</Packages>
<ProcessSteps>
      <Rows>
            <Row>
                  <Step>
                        <StepName>1 - x</StepName>
                  </Step>
                  <Step>
                        <StepName>2 - y</StepName>
                  </Step>
                  <Step>
                        <StepName>3 - z</StepName>
                  </Step>
            </Row>
      </Rows>
</ProcessSteps>
<Dates>
      <Rows>
            <Row>
                  <Date>
                        <Package>A</Package>
                        <Step>1 - x</Step>
                        <Comment>blah 1</Comment>
                  </Date>
                  <Date>
                        <Package>A</Package>
                        <Step>2 - y</Step>
                        <Comment>blah 2</Comment>
                  </Date>
                  <Date>
                        <Package>B</Package>
                        <Step>1 - x</Step>
                        <Comment>blah 3</Comment>
                  </Date>
            </Row>
      </Rows>
</Dates>

Basically at the end the row (for-each package) I want to display the comment whose step index (before the '-') is highest.
My current code will give me, in the case of Package A: "blah 1 blah 2" when I want only "blah 2"

* there is more data in all of the lists, but these fields are the ones used in this part of the stylesheel.
<xsl:choose>
	<xsl:when test="count($Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')])">
		<xsl:for-each select="$Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')]">
			<xsl:value-of select="substring-before(substring-after(@Comment,'&gt;'),'&lt;')"/><br/>
		</xsl:for-each>
	</xsl:when>
	<xsl:otherwise>
		-<!-- NO VALUE TEXT HERE -->
	</xsl:otherwise>
</xsl:choose>

Open in new window

0
 
LVL 11

Assisted Solution

by:andrei_teodorescu
andrei_teodorescu earned 120 total points
ID: 24865125
you still need to sort, but you have to sort before making the test
I still don't get it; the DVWP is showing data from a list or from an aggregate of 3 lists? You said that some columns are lookup type...
0
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 

Author Comment

by:RobertNoble
ID: 24872013
For the sort, idk how to get it to grab the first element only... using [1] grabs the first element before sorting the data.
You're correct, The data source is joined, and was created in SPD 2007.  
The reason is that the row headers are in one list, the column headers in another, and the data in a 3rd list for a pseud-franken-crosstab view.
Maybe using a siblings-type function or ddwrt:max could be helpful? But I've no experience or idea how to use these, and have not had time to look it up yet.
0
 
LVL 11

Expert Comment

by:andrei_teodorescu
ID: 24872120
please provide me with some more info; how are the lists defined in SHP and the source code of your DVWP
0
 

Author Comment

by:RobertNoble
ID: 24879193
here's the declarations of the variables from the previous code.

what do you mean "how are the lists defined?"  I setup a joined datasource in SPD 2007 with the fields I needed for the view.
// Defined at the top of the <XSL>
<xsl:variable name="Dates" select="/dsQueryResponse/RFPDates2/Rows/Row"/>
// Defined at the beginning of each <TR> before calling the date-calling template
<xsl:with-param name="Pkg" select="@Package_x002e_FullName"/>
<!-- -->
<xsl:choose>
        <xsl:when test="count($Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')])">
                <xsl:for-each select="$Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')]">
                        <xsl:value-of select="substring-before(substring-after(@Comment,'&gt;'),'&lt;')"/><br/>
                </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
                -<!-- NO VALUE TEXT HERE -->
        </xsl:otherwise>
</xsl:choose>

Open in new window

0
 

Author Comment

by:RobertNoble
ID: 24879213
I'm basically iterating through the parent lists for each of the packages and steps, since there is not necessarily a date item which matches each pkg/step pair, and need blank space to be present when this is the case.
0
 

Author Comment

by:RobertNoble
ID: 24895023
My latest thought was to use ddwrt:max() on the lookup value and test if it matches the current value to display only th highest value.  The pseudocode is commented out cause I can't seem to get it to work properly.

The datestep field is a lookup to another list, where it combined a sort value and a title.  I've tried using substring to extract only the number and convert it back to an int with number() to apply max() but with no success.
<xsl:when test="count($Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')])">
     <xsl:for-each select="$Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')]">
<!-- If this->datestep = max(datestep) then do the following display -->
          <xsl:value-of select="substring-before(substring-after(@Comment,'&gt;'),'&lt;')"/><br/>
     </xsl:for-each>
</xsl:when>

Open in new window

0
 

Accepted Solution

by:
RobertNoble earned 0 total points
ID: 24895100
I've got it.  for future reference.

The key is taking only the first element AFTER sorting the data.  using a [1] in the for-each doesn't work, because the data only gets sorted after that condition is filled.

by keeping only position() = 1 using and if clause after sorting descending, only the highest-value step is kept (since the step name is prefixed with a sort index)

Code Below
<xsl:when test="count($Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')])">
	<xsl:for-each select="$Dates[@Package = $Pkg and substring-before(substring-after(@Comment,'&gt;'),'&lt;')]">
	<xsl:sort select="@DateStep" order="descending"/>
		<xsl:if test="position() = 1">
			<xsl:value-of select="substring-before(substring-after(@Comment,'&gt;'),'&lt;')"/>
		</xsl:if>
	</xsl:for-each>
</xsl:when>

Open in new window

0
 
LVL 11

Expert Comment

by:andrei_teodorescu
ID: 24895142
Hi,

Sorry, but I had other things over my head during the past days; glad you found your answer.
0

Featured Post

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Re-position sub-options beneath the TAB 7 90
Automating receiving uploaded files via HTTPS instead of SFTP 3 44
XML XSL Choose example 3 25
Help with Syntax 9 37
Browsers only know CSS so your awesome SASS code needs to be translated into normal CSS. Here I'll try to explain what you should aim for in order to take full advantage of SASS.
Many times as a report developer I've been asked to display normalized data such as three rows with values Jack, Joe, and Bob as a single comma-separated string such as 'Jack, Joe, Bob', and vice versa.  Here's how to do it. 
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to count occurrences of each item in an array.

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question