XSL: Print divider by checking variables - xslt

I'm new to XSL and i want to do something like
var oldvalue= ''
for each
get currentvalue
if (oldvalue != currentvalue)
{
print divider
oldvalue = currentvalue
}
end for
I've tried it with
<xsl:variable name="oldname" select="name" />
<xsl:for-each select="myxpathstring">
<xsl:choose>
<xsl:when test="$newname = $newname">
<xsl:variable name="oldname" select="$newname" />
<div class='divider'>divider stuff </div>
</xsl:when>
<xsl:otherwise>No</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
But that doesn't work because i can't update the 'oldname' variable.
Anyone have a solution ?
The complete XSL (with JSP-parameters because i generate the XSL dynamically)
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="counter" select="count(<%= request.getParameter("xpath")%>)" />
<div id='counter' class='ui-state-highlight ui-corner-all'><p><span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"></span><xsl:value-of select="$counter"/> schema's gevonden</p></div>
<div class="page_navigation ui-widget-header ui-corner-all"></div>
<ul id='schemeslist' class="content">
<xsl:for-each select="<%= request.getParameter("xpath")%>"><!-- filter on sports //scheme[ (sports/sport ='Fietsen') and (planduration=12 or planduration=16)]-->
<xsl:sort select="name"/>
<!-- ////////////////// -->
<!-- print divider if name is new -->
<!-- ////////////////// -->
<li class='scheme' id='scheme'>
<div class='schemeSports'>
<!-- <xsl:for-each select="sports/sport">
<xsl:value-of select="."/>
</xsl:for-each> -->
<xsl:value-of select="sport"/>
</div>
<xsl:variable name="theid" select="#id" />
<div class='schemeName'><xsl:value-of select="name"/></div>
<div class='planDuration'><xsl:value-of select="planduration"/></div>
<div class='fitnessLevel'><xsl:value-of select="fitnesslevel"/></div>
<div class='order'>
<xsl:if test="price != ''"><xsl:value-of select="price"/>euro</xsl:if>
<button class='more' onClick='showInfo("{$theid}")' id='{$theid}'>MEER</button> <button class='buy' onClick='window.location = "buy.html?ID={$theid}"'>KOOP</button>
</div>
</li>
</xsl:for-each>
</ul>
<div style='clear:both'></div>
<div class="page_navigation ui-widget-header ui-corner-all"></div>
</xsl:template>
</xsl:stylesheet>
and here is a sample of the complete xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<schemes lang='nl-BE'>
<scheme id='5E47B7E9'>
<sport>Fietsen</sport>
<author>Energy Lab</author>
<name>Voorbereiding op de Ronde van Vlaanderen</name>
<planduration>16</planduration>
<fitnesslevel>Beginner</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>12</price>
<description>
<![CDATA[...]]>
</description>
</scheme>
<scheme id='5E47B7E9'>
<sport>Triatlon</sport>
<author>Energy Lab</author>
<name>Voorbereiding op de Ronde van Vlaanderen</name>
<planduration>16</planduration>
<fitnesslevel>Expert</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>12</price>
<description>
<![CDATA[...]]>
</description>
</scheme>
<scheme id='5E47B7E9'>
<sport>Fietsen</sport>
<author>Energy Lab</author>
<name>Voorbereiding op een Triatlon</name>
<planduration>24</planduration>
<fitnesslevel>Beginner</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>48</price>
<description>
<![CDATA[...]]>
</description>
</scheme>
</schemes>

Create a function that returns the new value, taking as parameters the old value and the list of values in myxpathstring.

If I understand your XSLT correct you have to use muenchian grouping. Read this article for a description of how this method works.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<schemes lang='nl-BE'>
<scheme id='5E47B7E9'>
<sport>Fietsen</sport>
<author>Energy Lab</author>
<name>Voorbereiding op de Ronde van Vlaanderen</name>
<planduration>16</planduration>
<fitnesslevel>Beginner</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>12</price>
<description><![CDATA[...]]></description>
</scheme>
<scheme id='5E47B7E9'>
<sport>Triatlon</sport>
<author>Energy Lab</author>
<name>Voorbereiding op de Ronde van Vlaanderen</name>
<planduration>16</planduration>
<fitnesslevel>Expert</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>12</price>
<description><![CDATA[...]]></description>
</scheme>
<scheme id='5E47B7E9'>
<sport>Fietsen</sport>
<author>Energy Lab</author>
<name>Voorbereiding op een Triatlon</name>
<planduration>24</planduration>
<fitnesslevel>Beginner</fitnesslevel>
<frequency>1-3</frequency>
<longtraining></longtraining>
<rollers>Ja</rollers>
<price>48</price>
<description><![CDATA[...]]></description>
</scheme>
</schemes>
XSLT:
I replaced the first jsp-tag with a dot and removed the second because I have no idea what you try to achieve with. I do not recommend dynamic *.xsl. You better put these information in your input.xml and query it with xpath.
<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='xml' indent='yes' omit-xml-declaration='yes'/>
<xsl:key name='schemata' match='scheme' use='name'/>
<xsl:template match='scheme'>
<li class='scheme' id='scheme'>
<div class='schemeSports'>
<xsl:value-of select="sport"/>
</div>
<xsl:variable name="theid" select="#id"/>
<div class='schemeName'>
<xsl:value-of select="name"/>
</div>
<div class='planDuration'>
<xsl:value-of select="planduration"/>
</div>
<div class='fitnessLevel'>
<xsl:value-of select="fitnesslevel"/>
</div>
<div class='order'>
<xsl:if test="price != ''">
<xsl:value-of select="price"/>
euro
</xsl:if>
<button class='more' onClick='showInfo("{$theid}")' id='{$theid}'>MEER</button>
<button class='buy' onClick='window.location = "buy.html?ID={$theid}"'>KOOP</button>
</div>
</li>
</xsl:template>
<xsl:template match='/schemes'>
<xsl:variable name="counter" select="count(.)"/> <!-- jsp -->
<div id='counter' class='ui-state-highlight ui-corner-all'>
<p>
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"/>
<xsl:value-of select="$counter"/>
<xsl:text> schema's gevonden</xsl:text>
</p>
</div>
<div class="page_navigation ui-widget-header ui-corner-all"/>
<ul id='schemeslist' class="content">
<!-- muenchian grouping -->
<xsl:for-each select='scheme[generate-id() = generate-id(key("schemata", name)[1])]'>
<xsl:sort select='name'/>
<xsl:if test='position() != 1'>
<div class='divider'/>
</xsl:if>
<xsl:apply-templates select='key("schemata", name)'/>
</xsl:for-each>
</ul>
<div style='clear:both'/>
<div class="page_navigation ui-widget-header ui-corner-all"/>
</xsl:template>
</xsl:stylesheet>
Result:
<div id="counter" class="ui-state-highlight ui-corner-all">
<p><span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"/>1 schema's gevonden</p>
</div><div class="page_navigation ui-widget-header ui-corner-all"/><ul id="schemeslist" class="content">
<li class="scheme" id="scheme">
<div class="schemeSports">Fietsen</div>
<div class="schemeName">Voorbereiding op de Ronde van Vlaanderen</div>
<div class="planDuration">16</div>
<div class="fitnessLevel">Beginner</div>
<div class="order">12
euro
<button class="more" onClick="showInfo("5E47B7E9")" id="5E47B7E9">MEER</button><button class="buy" onClick="window.location = "buy.html?ID=5E47B7E9"">KOOP</button></div>
</li>
<li class="scheme" id="scheme">
<div class="schemeSports">Triatlon</div>
<div class="schemeName">Voorbereiding op de Ronde van Vlaanderen</div>
<div class="planDuration">16</div>
<div class="fitnessLevel">Expert</div>
<div class="order">12
euro
<button class="more" onClick="showInfo("5E47B7E9")" id="5E47B7E9">MEER</button><button class="buy" onClick="window.location = "buy.html?ID=5E47B7E9"">KOOP</button></div>
</li>
<div class="divider"/>
<li class="scheme" id="scheme">
<div class="schemeSports">Fietsen</div>
<div class="schemeName">Voorbereiding op een Triatlon</div>
<div class="planDuration">24</div>
<div class="fitnessLevel">Beginner</div>
<div class="order">48
euro
<button class="more" onClick="showInfo("5E47B7E9")" id="5E47B7E9">MEER</button><button class="buy" onClick="window.location = "buy.html?ID=5E47B7E9"">KOOP</button></div>
</li>
</ul><div style="clear:both"/><div class="page_navigation ui-widget-header ui-corner-all"/>

Related

XSL : Generated DOM seems in weird order

I'm experiencing an issue with an xsl cheatsheet. The generated DOM seems to be in wrong order. Here is my xsl :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="site-path" select="site-path" />
<xsl:param name="target" select="target" />
<xsl:param name="page-id" select="page-id" />
<xsl:variable name="portlet-id" select="portlet/portlet-id" />
<xsl:template match="portlet">
<xsl:variable name="device_class">
<xsl:choose>
<xsl:when test="string(display-on-small-device)='0'">hidden-xs</xsl:when>
<xsl:when test="string(display-on-normal-device)='0'">hidden-sm</xsl:when>
<xsl:when test="string(display-on-large-device)='0'">hidden-md</xsl:when>
<xsl:when test="string(display-on-xlarge-device)='0'">hidden-lg</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div class="portlet {$device_class}">
<xsl:if test="not(string(display-portlet-title)='1')">
<h3 id="article_{$portlet-id}" class="heading"><xsl:value-of disable-output-escaping="yes" select="portlet-name" /></h3>
</xsl:if>
<ul class="news-list gallery news-cards">
<xsl:apply-templates select="document-list-portlet/document" />
<xsl:text disable-output-escaping="yes">
<![CDATA[<div class="clearfix"> </div>]]>
</xsl:text>
</ul>
</div>
</xsl:template>
<xsl:template match="document">
<xsl:if test="not(string(document-xml-content)='null')">
<xsl:variable name="vignette-id" select="document-xml-content/article/article-vignette/file-resource/resource-document-id" />
<xsl:variable name="attribute-id" select="document-xml-content/article/article-vignette/file-resource/resource-attribute-id" />
<li class="news-list-card-item">
<a href="{$site-path}?document_id={document-id}&portlet_id={$portlet-id}" class="news-card">
<div style="background-image: url(document?id={$vignette-id}&id_attribute={$attribute-id}&working_content=true)" class="news-card-image" />
<div class="news-card-wrapper">
<div class="news-card-content">
<div class="news-card-category">
<span>Catégorie</span>
</div>
<div class="news-card-title">
<xsl:value-of select="document-xml-content/article/document-title" />
</div>
</div>
</div>
</a>
<xsl:if test="(string(resource-is-votable)='1')">
<br />
<xsl:variable name="resource-score" select="resource-score" />
<img src="images/local/skin/plugins/rating/stars_{$resource-score}.png" alt="Score" title="Score" />
</xsl:if>
<xsl:if test="(string(is-download-stat)='1')">
<br />
#i18n{rating.resource_vote.labelDownloadCount} : <xsl:value-of select="resource-download-stat" />
</xsl:if>
</li>
</xsl:if>
</xsl:template>
After the render, the generated DOM is :
<li class="news-list-card-item">
<a class="news-card" href="jsp/site/Portal.jsp?document_id=35&portlet_id=100">
</a>
<div class="news-card-image" style="background-image: url(document?id=35&id_attribute=64&working_content=true)">
<a class="news-card" href="jsp/site/Portal.jsp?document_id=35&portlet_id=100">
<div class="news-card-wrapper">
<div class="news-card-content">
<div class="news-card-category">
<span>Catégorie</span>
</div>
<div class="news-card-title">Artu avec vignette 2</div>
</div>
</div>
</a>
</div>
</li>
Here is the expected HTML :
<li class="news-list-card-item">
<a href="#" class="news-card">
<div class="news-card-wrapper">
<div style="background-image: url(../../modules/news-card/image.jpg)" class="news-card-image"></div>
<div class="news-card-content">
<div class="news-card-category"><span>Mobilité</span>
</div>
<div class="news-card-title">Découvrez les neuf Autolib' customisées qui vont sillonner Paris</div>
</div>
</div>
</a>
</li>
Differences are :
In the expected, you got :
li > a > div >div > div ...
In the generated you got :
li > a
div > a > div > div > div
HEre is a smaller reproductible example :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="portlet">
<div class="portlet">
<ul class="news-list gallery news-cards">
<xsl:apply-templates select="document-list-portlet/document" />
</ul>
</div>
</xsl:template>
<xsl:template match="document">
<li class="news-list-card-item">
<a class="news-card">
<div style="background-image: url(hello_world.png)" class="news-card-image" />
<div class="news-card-wrapper">
<div class="news-card-content">
<div class="news-card-category">
<span>Catégorie</span>
</div>
<div class="news-card-title">
Title
</div>
</div>
</div>
</a>
</li>
</xsl:template>
</xsl:stylesheet>
Here is an example data used to generate my DOM :
<?xml version="1.0" encoding="UTF-8"?>
<portlet>
<portlet-name>Actualités projet</portlet-name>
<portlet-id>100</portlet-id>
<page-id>1</page-id>
<plugin-name>document</plugin-name>
<display-portlet-title>0</display-portlet-title>
<display-on-small-device>1</display-on-small-device>
<display-on-normal-device>1</display-on-normal-device>
<display-on-large-device>1</display-on-large-device>
<display-on-xlarge-device>1</display-on-xlarge-device>
<document-list-portlet>
<document>
<document-id>35</document-id>
<document-date-publication>11/07/2017</document-date-publication>
<document-xml-content>
<article>
<document-id>35</document-id>
<document-title>Artu avec vignette 2</document-title>
<document-summary>Artu avec vignette 2</document-summary>
<document-date-begin>11/07/2017</document-date-begin>
<document-date-end>
<document-categories>
<article-url>http://</article-url>
<article-attachment>
<article-vignette>
<file-resource>
<resource-document-id>35</resource-document-id>
<resource-attribute-id>64</resource-attribute-id>
<resource-content-type>image/jpeg</resource-content-type>
</file-resource>
<file-size>134783</file-size>
</article-vignette>
<article-body>&lt;p&gt;Artu avec vignette 2&lt;/p&gt;</article-body>
</article-attachment>
</document-categories>
</document-date-end>
</article>
</document-xml-content>
</document>
</document-list-portlet>
</portlet>
I'm using Google Chrome 59.
I'm searching the issue since 2 days and i'm currently lost. Can you help me?
Thx,
SLED
I just solved my issue by adding a   in my background-image div :
<div class="news-card-wrapper">
<div style="background-image: url(document?id={$vignette-id}&id_attribute={$attribute-id}&working_content=true)" class="news-card-image" > </div>
<div class="news-card-content">
<div class="news-card-category">
<span>Catégorie</span>
</div>
<div class="news-card-title">
<xsl:value-of select="document-xml-content/article/document-title" />
</div>
</div>
</div>
Thanks for all your answer and for #MartinHonnen explaination.

XSLT for dynamic tree

You can see my xml patern sample below. Every manuel has chapter tags, chapter tags may have subchapter and checklist tags. There is no static depth, it may change document to document, so I couldnt write the dynamic recursive xslt code to generate Html. Does anyone knows, how can I achive this.
<manuel name="Test">
<chapter name="00">
<subchapter name="00.01">
<checklist name="00.01.01">
<summary>abc</summary>
</checklist>
</subchapter>
<subchapter name="00.02">
<checklist name="00.02.01">
<summary>def</summary>
</checklist>
<subchapter name="00.02.02">
<checklist name="00.02.02.01">
<summary>xyz</summary>
</checklist>
</subchapter>
</subchapter>
<checklist name="00.03">
<summary>ZZZZ</summary>
</checklist>
</chapter>
</manuel>
For this sample, I suppose this result. I can set the css style, its not important now. The problem is generating the structure.
<div class="cssChapter"> 00</div>
<div class="cssSubChapter"> 00.01 </div>
<div class="cssCheckList"> 00.01.01 </div>
<div class="cssSummary"> abc </div>
<div class="cssSubChapter"> 00.02 </div>
<div class="cssCheckList"> 00.02.01 </div>
<div class="cssSummary"> def </div>
<div class="cssSubChapter"> 00.02.02 </div>
<div class="cssCheckList"> 00.02.02.01 </div>
<div class="cssSummary"> xyz </div>
<div class="cssCheckList"> 00.03 </div>
<div class="cssSummary"> ZZZZ</div>
Use a simple apply-templates:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="manuel">
<xsl:apply-templates select=".//*"/>
</xsl:template>
<xsl:template match="chapter">
<div class="cssChapter">
<xsl:value-of select="#name"/>
</div>
</xsl:template>
<xsl:template match="subchapter">
<div class="cssSubChapter">
<xsl:value-of select="#name"/>
</div>
</xsl:template>
<xsl:template match="checklist">
<div class="cssChecklist">
<xsl:value-of select="#name"/>
</div>
</xsl:template>
<xsl:template match="summary">
<div class="cssSummary">
<xsl:value-of select="."/>
</div>
</xsl:template>
</xsl:transform>
Online at http://xsltransform.net/3NJ3915/1.

xslt - Date Format

I'm having some issue with my xslt code and I was Wondering if someone could take a look. I think the problem is with the date formatting but i'm not sure.
I need to format a datetime into a day and month.
this is my code:
<xsl:stylesheet
version="1.0"
exclude-result-prefixes="x d xsl msxsl cmswrt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
<xsl:template name="NewsAndEvents" match="Row[#Style='NewsAndEvents']" mode="itemstyle">
<xsl:variable name="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title"/>
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ArticleDate">
<xsl:value-of select="#SongDate"/>
</xsl:variable>
<xsl:if test="string-length($SafeImageUrl) != 0">
<div class="event-contain">
<div class="event-img pull-right">
<div class="white-box">
<h1><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'MMMM')"/></h1>
<h2><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/></h2>
</div>
<img src="{$SafeImageUrl}" title="{#ImageUrlAltText}">
<xsl:if test="$ImageWidth != ''">
<xsl:attribute name="width">
<xsl:value-of select="$ImageWidth" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$ImageHeight != ''">
<xsl:attribute name="height">
<xsl:value-of select="$ImageHeight" />
</xsl:attribute>
</xsl:if>
</img>
</div>
<div class="text-sec pull-right">
<header>
<hgroup>
<h3 class="ttl md fnt-bld blue"> <xsl:value-of select="$DisplayTitle"/> </h3>
<h4 class="ttl sm fnt-bld blue-mob"> <xsl:value-of select="#SongDescription"/> </h4>
</hgroup>
</header>
<div class="row dynamic-text-contain pull-right">
<p class="ttl xs">
<span class="display-on-mob"><xsl:value-of select="#NewsDescription" /></span>
</p>
</div>
<div class="row">
<div class="display-all read-more-eruim no-mob">
<div class="display-more open-link">
<a>
<i class="icon-icons2-50"></i>
<p>
<span class="btn-text">Show All</span>
<i class="icon-icons2-10 left-arrow" id="arrow"></i>
</p>
</a>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="line"></div>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Tnx For the Help Yotam.
I Have a Solution If any one ever has this problem:
the thing is that:
<xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/>
is the wrong syntax and should be :
<xsl:value-of select="ddwrt:FormatDateTime(string($ArticleDate),1037, 'd')"/>
Now, another thing is that it returns the value as: dd/mm/yyyy and I only wanted the day so I used a sub string function like so:
<xsl:value-of select="substring-before(ddwrt:FormatDateTime(string($ArticleDate),1037, 'd'),'/')"/>
This Solved me this issue :)

XSLT For-Each Wrapping every nth item in a div

I have a series of nodes that are direct child nodes to a parent I want to loop over those nodes but have them wrapped in 'groups' of 4... I'm probably not wording this very clearly so this might help;
<span class="child01">#nodename</span>
<span class="child02">#nodename</span>
<span class="child03">#nodename</span>
<span class="child04">#nodename</span>
<span class="child05">#nodename</span>
<span class="child06">#nodename</span>
<span class="child07">#nodename</span>
<span class="child08">#nodename</span>
..
<span class="child32">#nodename</span>
<span class="child33">#nodename</span>
..and so on
Goal
<div class="group">
<span class="child01">#nodename</span>
<span class="child02">#nodename</span>
<span class="child03">#nodename</span>
<span class="child04">#nodename</span>
</div>
<div class="group">
<span class="child05">#nodename</span>
<span class="child06">#nodename</span>
<span class="child07">#nodename</span>
<span class="child08">#nodename</span>
</div>
<div class="group">
..
<span class="child32">#nodename</span>
</div>
<div class="group">
<span class="child33">#nodename</span>
..and so on
I have tried variations on this idea - wrapping the lot in the open and closing group tags and every fourth loop drop in a new close / open pair
<div class="group">
<xsl:for-each select="$currentPage/*">
<span>
<xsl:value-of select="#nodeName" />
</span>
<!--
=============================================================
After very 4th item
=============================================================
-->
<xsl:if test="position() mod 4 = 0">
<xsl:text></div><div class="page"></xsl:text>
</xsl:if>
</xsl:for-each>
</div>
But essentially it seems XSLT won't let me start with a closing unmatched tag
The clkoset solution I ahve found so far is a 'fix' in jquery Wrapping a div around every three divs but I would rather not rely on javascript to format the page.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pNumCols" select="3"/>
<xsl:template match="/*">
<xsl:apply-templates select="span[position() mod $pNumCols = 1]"/>
</xsl:template>
<xsl:template match="span">
<div>
<xsl:copy-of select=
".|following-sibling::span[not(position() > $pNumCols -1)]"/>
</div>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<t>
<span class="child01">#nodename</span>
<span class="child02">#nodename</span>
<span class="child03">#nodename</span>
<span class="child04">#nodename</span>
<span class="child05">#nodename</span>
<span class="child06">#nodename</span>
<span class="child07">#nodename</span>
<span class="child08">#nodename</span> ..
<span class="child32">#nodename</span>
<span class="child33">#nodename</span>
</t>
produces the wanted result:
<div>
<span class="child01">#nodename</span>
<span class="child02">#nodename</span>
<span class="child03">#nodename</span>
</div>
<div>
<span class="child04">#nodename</span>
<span class="child05">#nodename</span>
<span class="child06">#nodename</span>
</div>
<div>
<span class="child07">#nodename</span>
<span class="child08">#nodename</span>
<span class="child32">#nodename</span>
</div>
<div>
<span class="child33">#nodename</span>
</div>
If like me you need to transform the source elements that are being divided by position, use xsl:for-each instead of xsl:copy:
<xsl:template match="span">
<ol>
<xsl:for-each select=".|following-sibling::span[not(position() > $pNumCols -1)]"/>
<li><xsl:value-of select="./text()"/></li>
</xsl:for-each>
</ol>
</xsl:template>
Faced by the same problem, that is wanting to output
<div class="container">
<div class="row">
<div class="col">...</div>
<div class="col"/>...</div>
</div>
<div class="row">
...
</div>
</div>
from a CXML (Collection XML) file (http://gallery.clipflair.net/collection/activities.cxml - the data behind the PivotViewer display at http://gallery.clipflair.net/activity)
I coined up the following, based on other suggestions here, but using "mode" attribute of "template" and "apply-templates" XSL tags instead which make it cleaner I believe:
<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml http://gallery.clipflair.net/collection/activities.cxml?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cxml="http://schemas.microsoft.com/collection/metadata/2009"
exclude-result-prefixes="cxml"
>
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="COLUMNS" select="2"/>
<!-- ########################### -->
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ClipFlair Activities</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Collection">
<div class="container">
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Items">
<xsl:apply-templates select="cxml:Item[position() mod $COLUMNS = 1]" mode="row"/>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Item" mode="row">
<div class="row">
<div>----------</div>
<xsl:apply-templates select=".|following-sibling::cxml:Item[position() < $COLUMNS]" mode="col"/>
</div>
</xsl:template>
<xsl:template match="cxml:Item" mode="col">
<xsl:variable name="URL" select="#Href"/>
<xsl:variable name="FILENAME" select="cxml:Facets/cxml:Facet[#Name='Filename']/cxml:String/#Value"/>
<div class="col">
<xsl:value-of select="$FILENAME"/> --- <xsl:value-of select="$URL"/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()|#*">
</xsl:template>
</xsl:stylesheet>
the output from the above when run in Altova XMLSpy tool (note that it uses altova_samplexml processor instruction to find the XML data) is:
2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair --- http://studio.clipflair.net/?activity=2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair
Abu_Dukhan-CapRev-A1-AR.clipflair --- http://studio.clipflair.net/?activity=Abu_Dukhan-CapRev-A1-AR.clipflair
----------
AFarewellToArms-RevCap-C2-EN.clipflair --- http://studio.clipflair.net/?activity=AFarewellToArms-RevCap-C2-EN.clipflair
agComhaireamhCountingRND.clipflair --- http://studio.clipflair.net/?activity=agComhaireamhCountingRND.clipflair
----------
Al-imtihan-CapRev-B1-AR.clipflair --- http://studio.clipflair.net/?activity=Al-imtihan-CapRev-B1-AR.clipflair
AlBar-Cap-B1-B2-IT.clipflair --- http://studio.clipflair.net/?activity=AlBar-Cap-B1-B2-IT.clipflair
...

XSLT replace tag by generated one

I'm quite new to XSLT.
This is the problem I'm trying to solve for hours now:
I auto-generate a table of contents for a xml document which works great so far. However I'd like to replace a placeholder tag in my source xml with that just generated toc code.
So the output should include the whole document with replaced placeholder-toc-tag with the auto-generated toc xml.
This is what I've tried:
Let's say I have my placeholderTag anywhere in the document and want to replace this/those. I thought that I could loop through all nodes by node() and check if the node name equals my placeholder tag:
<xsl:template match="node()">
<xsl:choose>
<xsl:when test="divGen">
<!-- apply other template to generate toc-->
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
However the if statement won't match like this.
edit:
Ok, here's the source document (TEI coded - TEI namespace removed):
<TEI>
<teiHeader>
<fileDesc>
<titleStmt>
<title>Title</title>
</titleStmt>
<publicationStmt>
<p>Publication information</p>
</publicationStmt>
<sourceDesc>
<p>Information about the source</p>
</sourceDesc>
</fileDesc>
</teiHeader>
<text>
<front>
<titlePage>
<byline>title page details</byline>
</titlePage>
</front>
<body>
<divGen type="toc"/>
<div type="part">
<div type="section">
<head>heading1</head>
</div>
<div type="section">
<head>heading2</head>
</div>
</div>
<div type="part">
<div type="section">
<head>heading3</head>
</div>
<div type="section">
<head>heading4</head>
</div>
<div type="section">
<head>heading5</head>
</div>
</div>
</body>
<back> </back>
</text>
I'd like to auto-generate the toc from the head values and replace the divGen tag by the auto-produced toc code. However please notice that the divGen tag can be anywhere in the document but not outside of body.
Any ideas?
Chris
Good question, +1.
Here is a complete transformation (with mock TOC generation to be replaced by real one) that shows how to do this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vTOC">
<xsl:apply-templates mode="TOC"/>
<mockTOC>
<xsl:comment>The real TOC generated here</xsl:comment>
</mockTOC>
</xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="divGen[#type='toc']">
<xsl:copy-of select="$vTOC"/>
</xsl:template>
<xsl:template match="text()" mode="TOC"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<TEI>
<teiHeader>
<fileDesc>
<titleStmt>
<title>Title</title>
</titleStmt>
<publicationStmt>
<p>Publication information</p>
</publicationStmt>
<sourceDesc>
<p>Information about the source</p>
</sourceDesc>
</fileDesc>
</teiHeader>
<text>
<front>
<titlePage>
<byline>title page details</byline>
</titlePage>
</front>
<body>
<divGen type="toc"/>
<div type="part">
<div type="section">
<head>heading1</head>
</div>
<div type="section">
<head>heading2</head>
</div>
</div>
<div type="part">
<div type="section">
<head>heading3</head>
</div>
<div type="section">
<head>heading4</head>
</div>
<div type="section">
<head>heading5</head>
</div>
</div>
</body>
<back>
</back>
</text>
</TEI>
the correct, wanted output is produced, in which any occurences of <divGen type="toc"/> are replaced by the generated TOC:
<TEI>
<teiHeader>
<fileDesc>
<titleStmt>
<title>Title</title>
</titleStmt>
<publicationStmt>
<p>Publication information</p>
</publicationStmt>
<sourceDesc>
<p>Information about the source</p>
</sourceDesc>
</fileDesc>
</teiHeader>
<text>
<front>
<titlePage>
<byline>title page details</byline>
</titlePage>
</front>
<body>
<mockTOC><!--The real TOC generated here--></mockTOC>
<div type="part">
<div type="section">
<head>heading1</head>
</div>
<div type="section">
<head>heading2</head>
</div>
</div>
<div type="part">
<div type="section">
<head>heading3</head>
</div>
<div type="section">
<head>heading4</head>
</div>
<div type="section">
<head>heading5</head>
</div>
</div>
</body>
<back/>
</text>
</TEI>
Explanation: Use of modes to pre-generate the TOC in a variable, then overriding the identity rule for any TOC placeholder.
Im guessing somewhere u have a template like
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
then u want the template to only match your placeholderTag
then the others will default to your other nodes!
<xsl:template match="placeholderTag">
<!-- applying generate toc thing-->
</xsl:template>
<xsl:template match="node()">
<xsl:copy-of select="node()"/>
</xsl:template>