2

I'm working with the SharePoint content query web part. I have an HTML output which is desired to be

<ul>
<li>
    <img src="{RowAttribute-Url}" />
</li>
<li>
    <img src="{RowAttribute-Url}" />
</li>
</ul>
<table>
<tr>
<td>{RowAttribute-Title}</td>
<td>{RowAttribute-Title}</td>
</tr>
</table>

and the input xml for the CQWP is

<dsQueryResponse>
<Rows>
<Row ID="1" Title="Jane Doe" Modified="2010-10-14 14:05:14" Author="" Editor="" Created="2010-10-14 11:50:35"  ArticleStartDate="2010-10-01 00:00:00" Style="OutputTemplateName" GroupStyle="DefaultHeader" __begincolumn="True" __begingroup="False"></Row>
<Row ID="2" Title="John Doe" Modified="2010-10-14 14:05:29" Author="" Editor="" Created="2010-10-14 13:17:10" ArticleStartDate="2010-10-01 00:00:00"  Style="OutputTemplateName" GroupStyle="DefaultHeader" __begincolumn="False" __begingroup="False"></Row>
</Rows>
</dsQueryResponse>

So you can see that the web part will "tell" the xslt that it should render a particular style or output template. I'd like to re-run a second template on the rows and I thought that the easiest way to do this would be to replace the style attribute after the first run-through.

The first run through I'd like to render a series of li tags for each row and the second go through i'd like to do trs.

Is it possible to use xsl-copy to replace the "OutputTemplateName" prior to calling the ItemStyle template again?

Here is the xslt for the outer and inner stylesheets (inner being the itemstyles)

<xsl:template name="OuterTemplate">
    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
    <xsl:variable name="RowCount" select="count($Rows)" />
    <xsl:variable name="IsEmpty" select="$RowCount = 0" />
  <div id="container">
    <div id="inner-container">
                <xsl:choose>
                    <xsl:when test="$IsEmpty">
                         <xsl:call-template name="OuterTemplate.Empty" >
                             <xsl:with-param name="EditMode" select="$cbq_iseditmode" />
                         </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                         <xsl:call-template name="OuterTemplate.Body">
                             <xsl:with-param name="Rows" select="$Rows" />
                             <xsl:with-param name="FirstRow" select="1" />
                             <xsl:with-param name="LastRow" select="$RowCount" />
                        </xsl:call-template>                         
                    </xsl:otherwise>
                </xsl:choose>        
    </div>
  </div>
</xsl:template>


<xsl:template name="OuterTemplate.Body">
    <xsl:param name="Rows" />
    <xsl:param name="FirstRow" />
    <xsl:param name="LastRow" />
  <div id="container-rotator">
    <ul>
      <xsl:for-each select="$Rows">
          <xsl:variable name="CurPosition" select="position()" />
          <xsl:if test="($CurPosition &gt;= $FirstRow and $CurPosition &lt;= $LastRow)">              
              <xsl:call-template name="OuterTemplate.CallItemTemplate">
                  <xsl:with-param name="CurPosition" select="$CurPosition" />
              </xsl:call-template>               
          </xsl:if>
      </xsl:for-each>        
    </ul>
  </div>
  <h5>       
    <xsl:value-of select="ddwrt:FormatDateTime(string(/dsQueryResponse/Rows/Row[1]/@ArticleStartDate), 1033, 'MMMM')"/></h5>
  <table>
    <!-- before calling this foreach.. would i do the copy? -->
    <xsl:for-each select="$Rows">
      <xsl:variable name="CurPosition" select="position()" />
      <xsl:if test="($CurPosition &gt;= $FirstRow and $CurPosition &lt;= $LastRow)">
        <xsl:call-template name="OuterTemplate.CallItemTemplate">
          <xsl:with-param name="CurPosition" select="$CurPosition" />
        </xsl:call-template>            
      </xsl:if>
    </xsl:for-each>
  </table>
  <div>
    <a title="" href="/sites/sitename/Pages/page.aspx" target="">A Page Link</a>
  </div>
  <div>
    <a href="#">Another Page</a>
  </div>
</xsl:template>

And then the item template is below this is the template that i'd like to nearly duplicate but instead use trs and also provide a new "Style"

<xsl:template name="OutputTemplateName" match="Row[@Style='OutputTemplateName']" mode="itemstyle">
    <xsl:param name="CurPos" />
    <xsl:choose>      
    <xsl:when test="$CurPos = 1">
      <li class="show">
        <img src="{$SafeImageUrl}" />
      </li> 
    </xsl:when>
    <xsl:otherwise>
      <li>
         <img src="{$SafeImageUrl}" />
      </li>      
    </xsl:otherwise>
    </xsl:choose>   
  </xsl:template>

So, in summary, I have a series of rows that i'd like to put into firstly, an unordered list and then later into a table... all of this is outputted as HTML but i can only send it into one outer transform.

Even any conceptual suggestions would be helpful. I'll continue to update this post as I discover more.

BELOW I USED THE ACCEPTED ANSWER TO DO THE FOLLOWING **

Using the answer below I'll illustrate the changes needed to the above.

In the main wrapper xslt I did the following.

<xsl:template name="OuterTemplate.CallItemTemplate">
<xsl:param name="CurPosition" />
<xsl:param name="Mode" />
<xsl:choose>
  <xsl:when test="$Mode = 'table'">
    <xsl:apply-templates select="." mode="table">
      <xsl:with-param name="CurPos" select="$CurPosition" />
    </xsl:apply-templates>
  </xsl:when>
  <xsl:when test="$Mode = 'listitem'">
    <xsl:apply-templates select="." mode="listitem">
      <xsl:with-param name="CurPos" select="$CurPosition" />
    </xsl:apply-templates>
  </xsl:when>
  <xsl:otherwise>
    <xsl:apply-templates select="." mode="itemstyle">
    </xsl:apply-templates>
  </xsl:otherwise>
</xsl:choose>

And then i have two item templates instead of one.

<xsl:template name="TemplateNameList" match="Row[@Style='TemplateName']" mode="listitem">
<xsl:param name="CurPos" />
<xsl:variable name="SafeImageUrl">
  <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
    <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  </xsl:call-template>
</xsl:variable>
<xsl:choose>
  <xsl:when test="$CurPos = 1">
    <li class="show">
      <img src="{$SafeImageUrl}" />
    </li>
  </xsl:when>
  <xsl:otherwise>
    <li>
      <img src="{$SafeImageUrl}" />
    </li>
  </xsl:otherwise>
</xsl:choose>

Famous Nerd
  • 416
  • 4
  • 12
  • Not clear what you want. Please, provide the source XML document on which the transformation is to be applied. Also, for this exactly XML document provide the needed result from the transformation. Finally, describe the wanted properties of the transformation. – Dimitre Novatchev Oct 14 '10 at 22:44
  • Just a minor. I've seen your edit with modes. I think this didn¡t help you to reduce your stylesheet logic. That must be because those named template... I think your stylesheet need a refactoring with more pattern matching... Also, mixing data and style information is not a good practice: you could have that style information into a layout document and then populate that document with data. –  Oct 15 '10 at 22:29

1 Answers1

3

From http://www.w3.org/TR/xslt#modes

Modes allow an element to be processed multiple times, each time producing a different result.

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="Rows">
        <ul>
            <xsl:apply-templates/>
        </ul>
        <table>
            <xsl:apply-templates mode="table"/>
        </table>
    </xsl:template>
    <xsl:template match="Row">
        <li>
            <xsl:value-of select="@Data1"/>
        </li>
    </xsl:template>
    <xsl:template match="Row" mode="table">
        <tr>
            <xsl:apply-templates select="@*" mode="table"/>
        </tr>
    </xsl:template>
    <xsl:template match="Row/@*" mode="table">
        <td>
            <xsl:value-of select="."/>
        </td>
    </xsl:template>
</xsl:stylesheet>

With this input:

<Rows>   
  <Row Style="OutputTemplateName" Data1="Data1Value" Data2="Data2Value" />   
  <Row Style="OutputTemplateName" Data1="Data1Value" Data2="Data2Value" />   
</Rows>  

Output:

<ul>
    <li>Data1Value</li>
    <li>Data1Value</li>
</ul>
<table>
    <tr>
        <td>OutputTemplateName</td>
        <td>Data1Value</td>
        <td>Data2Value</td>
    </tr>
    <tr>
        <td>OutputTemplateName</td>
        <td>Data1Value</td>
        <td>Data2Value</td>
    </tr>
</table>
  • very cool... modes! I noticed those modes in the SharePoint original XSLT but I did not know their purpose. – Famous Nerd Oct 14 '10 at 23:05
  • What I did was "duplicate" my item template. give it a new name but a different mode. and ensured that when I called apply-templates for the second time I supplied the mode of "table" – Famous Nerd Oct 14 '10 at 23:31
  • @Famous Nerd: I'm glad it was helpfull. –  Oct 14 '10 at 23:33