xslt not transforming xml correctly in browser - xslt

I have the following XML:
<item>
<title>Testing WebForm</title>
<link>http://linkurlhere.com</link>
<description>
<div class="field field-name-body field-type-text-with-summary
field-label-hidden"><div class="field-items"><div class="field-item even"
property="content:encoded"><div style="background-color: white; width: 100%;">
<div id="prize" style="background-color: yellow; color: #660000; font-weight:
bold; width: 200px;">Prize here</div>
</div>
<div id="startDate">Start Date: January 1, 2013</div>
<div id="endDate">End Date: January 1, 2014</div>
<p></p>
<p>Thanks for playing please take the survey - mock intro</p>
</div></div></div></description>
</item>
And I am rendering it with the following XSLT:
<xsl:template match="rss/channel">
<div id="surveyList">
<p> Please
click on the survey below and complete the survey.</p>
<xsl:for-each select="item">
<div id="surveyItem">
<div id="thePrize">
<xsl:apply-templates select="description" />
</div>
<a id="surveyLink">
<xsl:attribute name="href">
<xsl:value-of select="link"
disable-output-escaping="yes" />
</xsl:attribute>
<xsl:attribute name="target">_blank</xsl:attribute>
<xsl:attribute name="title">Click to complete this survey</xsl:attribute>
<xsl:value-of select="title" disable-output-escaping="yes" />
</a>
<br />
</div>
</xsl:for-each>
</div>
</xsl:template>
<xsl:template match="rss/channel/item/description" name="description">
<xsl:value-of select=".//div[#id='prize']" disable-output-escaping="yes" />
</xsl:template>
When I run this through an IDE such as Altova, and transform it, it shows up correctly with the div prize text. However, when I build out the webapp and deploy it either locally on tomcat 6.0 or on an actual webserver the prize does not show up, and it is not in the source when I view the page.
I have tried multiple browsers to no avail. Is this a simple setup problem with my XSLT page?
Thanks.
Updated below with complete XML including RSS elements:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="http://drupal-survey.url" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>drupal-survey.url</title>
<link>http://drupal-survey.url</link>
<description></description>
<language>en</language>
<item>
<title>Testing WebForm</title>
<link>urlLink here</link>
<description>
<div class="field field-name-body field-type-text-with-summary field-label-hidden">
<div class="field-items"><div class="field-item even" property="content:encoded">
<div style="background-color: white; width: 100%;">
<div id="prize" style="background-color: yellow; color: #660000; font-weight: bold; width: 200px;">$1000 Gift Card to McDonald's</div>
</div>
<div id="startDate">Start Date: January 1, 2013</div>
<div id="endDate">End Date: January 1, 2014</div>
<p>Thanks for playing please take the survey - mock intro</p>
</div></div></div></description>
<pubDate>Mon, 25 Feb 2013 19:12:48 +0000</pubDate>
<dc:creator>admin</dc:creator>
<guid isPermaLink="false">6 at http://drupal-survey.url</guid>
</item>
<item>
<title>sss162 test</title>
<link>http://drupal-survey.url/sss162/test</link>
<description><div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>This is a testing paragraph</p>
<p>this is also</p>
</div></div></div></description>
<pubDate>Thu, 10 May 2012 19:24:43 +0000</pubDate>
<dc:creator>sss162</dc:creator>
<guid isPermaLink="false">4 at http://drupal-survey.url</guid>
</item>
<item>
<title>Orientation Survey</title>
<link>http://drupal-survey.url</link>
<description><div class="field field-name-body field-type-text-with-summary field-label-hidden">
<div class="field-items"><div class="field-item even" property="content:encoded"><div id="startDate">Start Date: January 1, 2013</div>
<div id="endDate">End Date: January 1, 2014</div>
<p>This may be the brief explanation paragraph.</p>
</div></div></div></description>
<pubDate>Thu, 10 May 2012 17:11:38 +0000</pubDate>
<dc:creator>admin</dc:creator>
<guid isPermaLink="false">2 at http://drupal-survey.url</guid>
</item>
</channel>
</rss>

Related

XSLT 1.0 Greedy knapsack grouping methods?

I have an XML dataset (provided from SharePoint 2007 to a DVWP) structured something like:
<Rows>
<Row ID="1" Spanoffset="0" Span="55" Spantail="55"/>
<Row ID="2" Spanoffset="30" Span="31" Spantail="61"/>
<Row ID="3" Spanoffset="61" Span="20" Spantail="81"/>
<Row ID="4" Spanoffset="82" Span="30" Spantail="112"/>
</Rows>
Say each row represents a bar that starts at #Spanoffset and is #Span wide, #Spantail is there so I don't have to calculate it if I need it. I am trying to pack the rows together efficently so that rows that wont overlap get grouped together. The dataset is pre-sorted by #Spanoffset. This is essentially a knapsack problem as each Row could fit in multiple possible groups. What I want to do is a simple greedy solution, and know how I could code it in say c# or java, but since I cannot mark nodes as visited (well I can, but I lose it when I come back up the recursion tree) and I cannot seem to remove nodes as I visit them, I am at a loss for how to approach this.
For example the above data would look something like this:
<div style="clear:both">
<div style="width: 110px; margin-left: 0px; float:left;">1</div>
<div style="width: 40px; margin-left: 12px; float:left;">3</div>
<div style="width: 60px; margin-left: 2px; float:left;">4</div>
</div>
<div style="clear:both">
<div style="width: 62px; margin-left: 60px; float:left;">2</div>
</div>
I haven't been bothering trying to get the floats to work right as I have yet to be able to get the Row nodes to appear only one time each, in the right order. Once I get them there I am fairly certain I can get the formatting to work out.
The best XSLT I have come up with so far has been:
<xsl:template match="row">
<xsl:variable name="tail" select="#Spantail"/>
<div style="width:{2*#Span}px;
left:{2*(#Spanoffset)}px;">
<xsl:value-of select="#ID"/>
</div>
<xsl:apply-templates select="(following-sibling::row)[#Spanoffset>=$tail][1]"/>
</xsl:template>
Which generates
<div style="width: 110px;left: 0px">1</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 62px; left: 60px">2</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 40px; left: 122px">3</div>
<div style="width: 60px; left: 164px">4</div>
<div style="width: 60px; left: 164px">4</div>
So my problems are 2 (that I see) and I think they are intertwined.
1) How to fix/re-factor my template(s) to only emit each row once.
and
2) How to wrap the groupings in container <div> elements.
Been banging my head against this for 2 days, any one able to help?
Edit:
Well, after some sleep, I have the wrapping container by adding a boolean parameter to my template, and using some CDATA tags to emit <div> tags when its true. The boolean defaults to true, and when I call the nested apply-templates I set it to false, hence wrapping up the groups in containers. I still cant see a way of marking <Row>s as visited yet.
I think it's very tricky with just core XSLT, but it's easier with node-set(), a XSLT extension function:
<xsl:template name="add-row">
<xsl:param name="row"/>
<xsl:param name="prev-group" />
<xsl:if test="$row and not($row/#ID = $prev-group/Row/#ID)">
<xsl:copy-of select="$row" />
<xsl:call-template name="add-row">
<xsl:with-param name="row" select="$row/following-sibling::Row[#Spanoffset > $row/#Spantail][1]" />
<xsl:with-param name="prev-group" select="$prev-group" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="add-group">
<xsl:param name="first-row" />
<xsl:param name="prev-group" select="exsl:node-set(/)" />
<xsl:if test="$first-row">
<xsl:variable name="group">
<xsl:call-template name="add-row">
<xsl:with-param name="row" select="$first-row" />
<xsl:with-param name="prev-group" select="$prev-group" />
</xsl:call-template>
</xsl:variable>
<div clear="both">
<xsl:for-each select="exsl:node-set($group)/Row">
<div style="width: {2*#Span}px; left: {2*#Spanoffset}px"><xsl:value-of select="#ID"/></div>
</xsl:for-each>
</div>
<xsl:call-template name="add-group">
<xsl:with-param name="first-row" select="$first-row/following-sibling::Row[#Spanoffset < preceding-sibling::Row/#Spantail][1]" />
<xsl:with-param name="prev-group" select="exsl:node-set($group)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Rows">
<xsl:call-template name="add-group">
<xsl:with-param name="first-row" select="Row[1]" />
</xsl:call-template>
</xsl:template>
Don't forget to declare extension prefix and namespace in your stylesheet tag:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
extension-element-prefixes="exsl"
xmlns:exsl="http://exslt.org/common">
http://exslt.org/common is a valid namespace for Java XSLT processors, such as Xalan or Saxon; if you're using MSXML, use urn:schemas-microsoft-com:xslt instead.

get last item in content query web part using xslt (SharePoint 2010)

This is my first time that I am using Content Query Web part and xslt. I have to display the last 5 posts from a blog in the following fashion (please look at the image below):
The table contains two columns. In the left column I would like to display the last post and in the right column I would like to display the rest of the posts from a particual blog.
Edit 1
The source is just an OOTB Blog Site and I have added a few posts in it. I would like to display these posts in an html table which contains two columns. In the left column I would like to display the last post entered in the blog and in the right column I would like to loop through other posts. The user must specify how many posts he/she would like to see in the CQWP.
Edit 2
This is the xslt that I have created so far. The only think is that the table is being repeated multiple times, which I don't want that. There should be only one table. If you look in the xslt code I have manually entered some text, like Test1, test 2... In their place I would like to display the rest of the blog posts.
<xsl:template name="Post" match="Row[#Style='Post']" mode="itemstyle">
<xsl:variable name="SafeLinkUrl">
<xsl:call-template name="OuterTemplate.GetSafeLink">
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</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>
<div>
<table width="100%" cellpadding="2" cellspacing="2" border="1">
<tr>
<td colspan="2" valign="top">
<xsl:value-of select="#Author"/></td>
<td rowspan="2" valign="top" width="30%">
<div>
<b>Previous blog posts:</b>
</div>
<div>
<ul style="margin-left:-2px;">
<li>Test 1</li>
<li>Test 2</li>
<li>Test 3</li>
<li>Test 4</li>
</ul>
</div>
</td>
</tr>
<tr>
<td width="15%" valign="top">
image</td>
<td valign="top">
<div>
<xsl:value-of select="#Title"/>
</div>
<div class="custom_description">
<xsl:value-of select="#Body" disable-output-escaping="yes" />
</div>
<p>
<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
<a href="{$SafeLinkUrl}">
<xsl:if test="$ItemsHaveStreams = 'True'">
<xsl:attribute name="onclick">
<xsl:value-of select="#OnClickForWebRendering"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="$ItemsHaveStreams != 'True' and #OpenInNewWindow = 'True'">
<xsl:attribute name="onclick">
<xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
</xsl:attribute>
</xsl:if>
<br />
<b>Read More ></b>
</a>
</p>
</td>
</tr>
</table>
</div>
</xsl:template>
Edit 3
<root>
<Posts>
<Post ID="1">
<Title>this post 1</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="2">
<Title>this post 2</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="3">
<Title>this post 3</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="4">
<Title>this post 4</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="5">
<Title>this post 5</Title>
<Body>The comment comes here</Body>
</Post>
</Posts>
</root>
Thank you
First let me caveat emptor: I know nothing about SharePoint, and I do not have an installation of SharePoint installed. There is a StackExchange website which specialised in SharePoint questions, and this site may serve you better than SO. See https://sharepoint.stackexchange.com/questions/22465/recreating-the-blog-template
You should also take a look at http://www.glynblogs.com/2011/04/overriding-the-presentation-of-an-xslt-list-view-web-part.html .
UPDATE
This XSLT 1.0 style-sheet, for an MS XSLT processor...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="xsl msxsl">
<xsl:output method="html" doctype-system="" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:variable name="empty-main">
<empty-main>No content yet.</empty-main>
</xsl:variable>
<xsl:variable name="empty-sub">
<empty-main>No older content yet.</empty-main>
</xsl:variable>
<xsl:template match="/*">
<html>
<head>
<title>Blog</title>
<style type="text/css">
table {
width: 100%;
border: 1px solid #000;
}
td.main-col, td.subsiduary-col {
vertical-align:text-top;
}
td.main-col {
width: 75%
}
td.subsiduary-col {
width: 25%
}
</style>
</head>
<body>
<table border="1">
<tr>
<xsl:variable name="count-posts" select="count(msxsl:node-set(Posts/Post))" />
<td class="main-col">
<xsl:apply-templates select="
(Posts/Post[last()] | msxsl:node-set($empty-main))[1]" />
</td>
<td class="subsiduary-col">
<xsl:apply-templates select="
Posts/Post[position() > last() - 5 and position() < last()] |
msxsl:node-set($empty-sub)[$count-posts < 2]" />
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Post">
<xsl:apply-templates select="Title" />
<p><xsl:copy-of select="Body/node()" /></p>
</xsl:template>
<xsl:template match="Post[last()]/Title" priority="2">
<h1><xsl:value-of select="." /></h1>
</xsl:template>
<xsl:template match="Post/Title">
<h2><xsl:value-of select="." /></h2>
</xsl:template>
<xsl:template match="empty-main|empty-sub" priority="2">
<p><xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
...will transform this input...
<root>
<Posts>
<Post ID="1">
<Title>this post 1</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="2">
<Title>this post 2</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="3">
<Title>this post 3</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="4">
<Title>this post 4</Title>
<Body>The comment comes here</Body>
</Post>
<Post ID="5">
<Title>this post 5</Title>
<Body>The comment comes here</Body>
</Post>
</Posts>
</root>
..into this output...
<!DOCTYPE html SYSTEM "">
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Blog</title>
<style type="text/css">
table {
width: 100%;
border: 1px solid #000;
}
td.main-col, td.subsiduary-col {
vertical-align:text-top;
}
td.main-col {
width: 75%
}
td.subsiduary-col {
width: 25%
}
</style>
</head>
<body>
<table border="1">
<tr>
<td class="main-col">
<h1>this post 5</h1>
<p>The comment comes here</p>
</td>
<td class="subsiduary-col">
<h2>this post 1</h2>
<p>The comment comes here</p>
<h2>this post 2</h2>
<p>The comment comes here</p>
<h2>this post 3</h2>
<p>The comment comes here</p>
<h2>this post 4</h2>
<p>The comment comes here</p>
</td>
</tr>
</table>
</body>
</html>
For a visual of how this renders in a browser, paste the html output into http://htmledit.squarefree.com/ .
Displays the first or the last item depending on Sorting selected in the panel tool of the web part.
<xsl:if test="count(preceding-sibling::*)=0">
Example
<xsl:template name="DisplayPosts" match="Row[#Style='DisplayPosts']" mode="itemstyle">
<table width="100%" border="1">
<tr>
<td width="70%">
<xsl:if test="count(preceding-sibling::*)=0">
<xsl:value-of select="#Title" />
</xsl:if>
</td>
<td width="30%">
<xsl:if test="count(preceding-sibling::*)>0">
<xsl:value-of select="#Title" />
</xsl:if>
</td>
</tr>
</table>
</xsl:template>

XSL: Print divider by checking variables

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"/>

Choose from XML node with multiple category elements

I have an XML document with a collection of news articles that have been assigned to multiple categories. I now need to group these documents by category. Below is a sample item record:
<item>
<link>http://www.threelanews.com/articles/?id=50456</link>
<category>/General/</category>
<category>/Technology/</category>
<category>/Technology/Telecommunications/</category>
<category>/Technology/Information Technology/Internet/</category>
<title>Sony debuts handsets at CES</title>
<description>The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</description>
<pubDate>Tue, 10 Jan 2012 12:11:01 +0200</pubDate>
</item>
I am using an XSL stylesheet to transform the document. For each group, I will do a test to see what elements belong to that category and if there is a match in one of the category elements, the article should be added to the html eg:
<xsl:when test="contains(category,'/General/')">
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
<a href="{$linkUrl}" target="_blank">
<xsl:value-of select="title"/>
</a>
</div>
<xsl:if test="string-length($imageUrl) > 0">
<div class="news-item-image">
<img src="{$imageUrl}" />
</div>
</xsl:if>
<div class="news-item-description">
<xsl:value-of select="description"/>
</div>
</div>
<div class="clear" />
</xsl:when>
Then the article should be added to the "General Group". Articles with multiple categories should appear in each group that they are relevant. The above statement will work for the "General" group but when I try to do the same for "Technology" or the other categories below it, this article is not returned. I have found it is only doing the match on the first element. Is there any way I couuld do the match on all the category elements?
Try the following transforms:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Matched Items</h2>
<xsl:apply-templates select=
"//item[category/.='/General/']"/>
</body>
</html>
</xsl:template>
<xsl:template match="item">
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
<a href="{linkUrl}" target="_blank">
<xsl:value-of select="title"/>
</a>
</div>
<xsl:if test="string-length(imageUrl) > 0">
<div class="news-item-image">
<img src="{imageUrl}" />
</div>
</xsl:if>
<div class="news-item-description">
<xsl:value-of select="description"/>
</div>
</div>
<div class="clear" />
</xsl:template>
</xsl:stylesheet>
The important part is this XPath, which selects all item nodes that have a category with the given value:
//item[category/.='/General/']
Applying the transform to this document:
<items>
<item>
<link>http://www.threelanews.com/articles/?id=50456</link>
<category>/General/</category>
<category>/Technology/</category>
<category>/Technology/Telecommunications/</category>
<category>/Technology/Information Technology/Internet/</category>
<title>Sony debuts handsets at CES</title>
<description>The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</description>
<pubDate>Tue, 10 Jan 2012 12:11:01 +0200</pubDate>
</item>
<item>
<link>http://www.threelanews.com/articles/?id=50456</link>
<category>/Technology/</category>
<category>/Technology/Telecommunications/</category>
<category>/Technology/Information Technology/Internet/</category>
<title>Sony debuts handsets at CES</title>
<description>The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</description>
<pubDate>Tue, 10 Jan 2012 12:11:01 +0200</pubDate>
</item>
</items>
Gives the expected result:
<H2>Matched Items</H2>
<DIV class=news-item width="100%">
<DIV class=news-item-title width="100%"><A href="" target=_blank>Sony debuts handsets at CES</A></DIV>
<DIV class=news-item-description>The Xperia S will be available globally from the first quarter of 2012. Sony Ericsson will showcase the first handsets from...</DIV>
</DIV>
<DIV class=clear></DIV>
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:key name="kCategoryByVal" match="category"
use="substring-before(substring(.,2), '/')"/>
<xsl:template match=
"category
[generate-id()
=
generate-id(key('kCategoryByVal',
substring-before(substring(.,2), '/')
)
[1]
)
]
">
<xsl:variable name="vMainCat" select=
"substring-before(substring(.,2), '/')"/>
<h1><xsl:value-of select="$vMainCat"/></h1>
<xsl:apply-templates mode="inGroup" select=
"/*/item[category[starts-with(., concat('/', $vMainCat))]]"/>
</xsl:template>
<xsl:template match="item" mode="inGroup">
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
<a href="{link}" target="_blank">
<xsl:value-of select="title"/>
</a>
</div>
<xsl:apply-templates select="image[#url]" mode="inGroup"/>
<div class="news-item-description">
<xsl:value-of select="description"/>
</div>
</div>
<div class="clear" />
</xsl:template>
<xsl:template match="image" mode="inGroup">
<div class="news-item-image">
<img src="{#url}" />
</div>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on this XML document (derived from the provided, but made a little-bit more realistic):
<items>
<item>
<link>http://www.threelanews.com/articles/?id=50456</link>
<category>/General/</category>
<category>/Technology/</category>
<category>/Technology/Telecommunications/</category>
<category>/Technology/Information Technology/Internet/</category>
<title>Sony debuts handsets at CES</title>
<image url="http://www.blogcdn.com/www.engadget.com/media/2011/03/11x0328mar0424.jpg"/>
<description>The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</description>
<pubDate>Tue, 10 Jan 2012 12:11:01 +0200</pubDate>
</item>
<item>
<link>http://www.threelanews.com/articles/?id=50456</link>
<category>/Technology/</category>
<category>/Technology/Telecommunications/</category>
<category>/Technology/Information Technology/Internet/</category>
<title>Toshiba produces the next Portege</title>
<description>The next Portege will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</description>
<pubDate>Tue, 10 Jan 2012 12:11:01 +0200</pubDate>
</item>
</items>
the wanted result is produced (all different categories and the items in them):
<h1>General</h1>
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
Sony debuts handsets at CES
</div>
<div class="news-item-image">
<img src="http://www.blogcdn.com/www.engadget.com/media/2011/03/11x0328mar0424.jpg"/>
</div>
<div class="news-item-description">The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</div>
</div>
<div class="clear"/>
<h1>Technology</h1>
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
Sony debuts handsets at CES
</div>
<div class="news-item-image">
<img src="http://www.blogcdn.com/www.engadget.com/media/2011/03/11x0328mar0424.jpg"/>
</div>
<div class="news-item-description">The Xperia S will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</div>
</div>
<div class="clear"/>
<div class="news-item" width="100%">
<div class="news-item-title" width="100%">
Toshiba produces the next Portege
</div>
<div class="news-item-description">The next Portege will be available globally from the first quarter of 2012.
Sony Ericsson will showcase the first handsets from...</div>
</div>
<div class="clear"/>
Explanation:
All different main categories are found using Muenchian grouping.
For each of the main categories, all item elements that have a category with string value that makes the item in this main category, the item's data is output appropriately formatted.
In this solution an assumption is made that only "Main" categories (the starting category-name in a string that contains a category and subcategories) need be listed.

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>