XSLT if condition for no of nodes - xslt

I am relatively new to xslt ,I want to do something if the nodecount is not equal to 0,but XSLT not working for if condition
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link href="CSS.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="main_cont">
<div class="page3">
<xsl:if test="(Count(/PrecisionVestor/OtherIncomeSection/OtherIncome) != 0)">
<div class="rent_roll">
<div class="othr_inc">
<div class="fst_r_box">
<div class="fst_r_box_fst_row" style="width:100%; height:30px; float:left;">
<div class="item" style="width:25%; height:30px; float:left; line-height:30px;">Description</div>
<div class="cost" style="width:18%; height:30px; float:left; text-align:center; line-height:30px;">Monthly Rent</div>
<div class="cost" style="width:18%; height:30px; float:left; text-align:center; line-height:30px;">Lease Start</div>
<div class="cost" style="width:18%; height:30px; float:left; text-align:center; line-height:30px;">Lease End</div>
<div class="cost" style="width:18%; height:30px; float:left; text-align:center; line-height:30px; ">Escalator</div>
</div>
<xsl:for-each select="PrecisionVestor/OtherIncomeSection/OtherIncome">
<div class="fst_r_box_fst_row_inn">
<div class="item_b" style="width:25%; "><xsl:value-of select="Description"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="MonthlyRent"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="LeaseStart"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="LeaseEnd"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="Escalator"/></div>
</div>
</xsl:for-each>
<xsl:for-each select="PrecisionVestor/OtherIncomeSection/TotalOtherIncome">
<div class="fst_r_box_btm_row">
<div class="item_b" style="width:25%; "><xsl:value-of select="Description"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="MonthlyRent"/></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"></div>
<div class="cost_b" style="width:12%; margin-right:6%; text-align:right; float:left;"><xsl:value-of select="Escalator"/></div>
</div>
</xsl:for-each>
</div>
</div>
</xsl:if>
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Here is the xml for xslt
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="xslStyle1.xsl"?>
<PrecisionVestor>
<OtherIncomeSection>
<OtherIncome>
<Description>Rent</Description>
<MonthlyRent>200</MonthlyRent>
<LeaseStart>3/12/13</LeaseStart>
<LeaseEnd>3/12/14</LeaseEnd>
<Escalator>2</Escalator>
</OtherIncome>
<TotalOtherIncome>
<Description>Totals</Description>
<MonthlyRent>200</MonthlyRent>
<Escalator>2</Escalator>
</TotalOtherIncome>
</OtherIncomeSection>
</PrecisionVestor>
It is working fine until I added if condition once I add the if condition I am getting blank html

One problem is that you are using a capital C in Count when it should be:
<xsl:if test="count(/PrecisionVestor/OtherIncomeSection/OtherIncome) != 0">
But count() is not actually needed to check for node presence. You can instead simply do this:
<xsl:if test="/PrecisionVestor/OtherIncomeSection/OtherIncome">
Another problem that is causing the XSLT to fail is that you are missing a closing </div> tag before the <xsl:if> tag. If both of these issues are fixed, the XSLT should run.
I'd also suggest tidying the XSLT up a bit, like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<link href="CSS.css" rel="stylesheet" type="text/css" />
<style>
.item, .item_b { width: 25%; }
.item, .cost { height: 30px; float:left; line-height: 30px; }
.cost { width: 18%; text-align: center; }
.cost_b { width: 12%; margin-right: 6%; text-align: right; float: left; }
</style>
</head>
<body>
<div class="main_cont">
<div class="page3">
<xsl:apply-templates select="PrecisionVestor/OtherIncomeSection[OtherIncome]" />
</div>
</div>
</body>
</html>
</xsl:template>
<xsl:template match="OtherIncomeSection">
<div class="rent_roll">
<div class="othr_inc">
<div class="fst_r_box">
<div class="fst_r_box_fst_row" style="width:100%; height:30px; float:left;">
<div class="item">Description</div>
<div class="cost">Monthly Rent</div>
<div class="cost">Lease Start</div>
<div class="cost">Lease End</div>
<div class="cost">Escalator</div>
</div>
<xsl:apply-templates select="OtherIncome">
<xsl:with-param name="rowClass" select="'fst_r_box_fst_row_inn'" />
</xsl:apply-templates>
<xsl:apply-templates select="OtherIncome">
<xsl:with-param name="rowClass" select="'fst_r_box_btm_row'" />
</xsl:apply-templates>
</div>
</div>
</div>
</xsl:template>
<xsl:template match="OtherIncome | TotalOtherIncome">
<xsl:param name="rowClass" />
<div class="$rowClass">
<xsl:apply-templates select="Description | MonthlyRent" />
<xsl:apply-templates select="LeaseStart | LeaseEnd" />
<xsl:apply-templates select="self::TotalOtherIncome" mode="leaseColumns" />
<xsl:apply-templates select="Escalator" />
</div>
</xsl:template>
<xsl:template match="Description">
<div class="item_b">
<xsl:value-of select="."/>
</div>
</xsl:template>
<xsl:template match="MonthlyRent | LeaseStart | LeaseEnd | Escalator">
<div class="cost_b">
<xsl:value-of select="."/>
</div>
</xsl:template>
<xsl:template match="TotalOtherIncome" mode="leaseColumns">
<div class="cost_b"></div>
<div class="cost_b"></div>
</xsl:template>
</xsl:stylesheet>

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 Rename node's attribute value depending on ancestor's attribute value

I have a large number of html files like the following:
<html>
<body>
<div class="a">aaa
<div class="a1">a1a1a1</div>
<div class="a2">a2a2a2</div>
<div class="a2">a3a3a3</div>
</div>
<div class="v u">bbb
<div class="x">xxx</div>
<div class="y">yyy</div>
<div class="z">z1z1z1
<div class="w">www1</div>
<div class="w">www2</div>
<div class="w">www3</div>
</div>
<div class="z">z2z2z2
<div class="w">www4</div>
<div class="w">www5</div>
<div class="w">www6</div>
</div>
</div>
<div class="i">
<div class="j">jjj</div>
<div class="x">
<div class="k">
<div class="w">www7</div>
<div class="w">www8</div>
</div>
</div>
</div>
</body>
</html>
The classes x, y, z, and w can occur any number of times and with any div throughout the html.
There is one and only one div class="v u"
I would like to:
Rename the classes x, y, z, and w to b1, b2, b3, and b4 respectively if and only if any ancestor of that node is div class="v u"
Rename div class="v u" to div class="b"
The result would then be:
<html>
<body>
<div class="a">aaa
<div class="a1">a1a1a1</div>
<div class="a2">a2a2a2</div>
<div class="a2">a3a3a3</div>
</div>
<div class="b">bbb
<div class="b1">xxx</div>
<div class="b2">yyy</div>
<div class="b3">z1z1z1
<div class="b4">www1</div>
<div class="b4">www2</div>
<div class="b4">www3</div>
</div>
<div class="b3">z2z2z2
<div class="b4">www4</div>
<div class="b4">www5</div>
<div class="b4">www6</div>
</div>
</div>
<div class="i">
<div class="j">jjj</div>
<div class="x">
<div class="k">
<div class="w">www7</div>
<div class="w">www8</div>
</div>
</div>
</div>
</body>
</html>
I have tried the following xslt, that doesn't give me the expected result:
<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:template match="#*|node()" >
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='v u']">
<div class="b">
<xsl:copy-of select="node()" />
</div>
</xsl:template>
<xsl:template match="div[#class='v u']/div[#class='x']">
<div class="b1">
<xsl:copy-of select="node()" />
</div>
</xsl:template>
<xsl:template match="div[#class='v u']/div[#class='y']">
<div class="b2">
<xsl:copy-of select="node()" />
</div>
</xsl:template>
<xsl:template match="div[#class='v u']/div[#class='z']">
<div class="b3">
<xsl:copy-of select="node()" />
</div>
</xsl:template>
<xsl:template match="div[#class='v u']/div[#class='z']/div[#class='w']">
<div class="b4">
<xsl:copy-of select="node()" />
</div>
</xsl:template>
</xsl:stylesheet>
I think I understand why it is not giving me the correct result, however I do not seem to find the correct solution.
Instead of all those <xsl:copy-of select="node()" /> you need to use <xsl:apply-templates/> or <xsl:apply-templates select="node()"/> to keep the template based processing alive.

xslt adding constant number of siblings

I have a large number of files with a structure like the following a.html:
<html>
<body>
<div class="a">aaa
<div class="b">bbb</div>
<div class="c">ccc1
<div class="d">ddd11
<div class="e">eee11</div>
<div class="f">fff11
<div class="g">ggg111</div>
<div class="g">ggg112</div>
<div class="g">ggg113</div>
<div class="g">ggg114</div>
<div class="g">ggg115</div>
<div class="g">ggg116</div>
</div>
</div>
<div class="d">ddd12
<div class="e">eee12</div>
<div class="f">fff12
<div class="g">ggg121</div>
<div class="g">ggg122</div>
<div class="g">ggg123</div>
<div class="g">ggg124</div>
</div>
</div>
</div>
<div class="c">ccc2
<div class="d">ddd21
<div class="e">eee21</div>
<div class="f">fff21
<div class="g">ggg211</div>
<div class="g">ggg212</div>
<div class="g">ggg213</div>
<div class="g">ggg214</div>
<div class="g">ggg215</div>
</div>
</div>
</div>
...
</div>
</body>
</html>
The number of div class="c" is variable in each file (zero or more)
The number of div class="d" is variable inside each (zero or more)
The number of div class="g" is variable inside each (zero or more)
I would like to have a number of div class="c" equal to the max_c parameter in all files.
I use the following shell script to pass the max_c parameter with a value equal to 3:
#!/bin/bash
xsltproc --param max_c 3 a.xslt a.html
And I use the following a.xslt:
<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="max_c"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='a']">
<xsl:copy>
<xsl:apply-templates select="div[#class='a']" />
<xsl:apply-templates select="div[#class='b']" />
<xsl:apply-templates select="div[#class='c']" />
<xsl:call-template name="AddC">
<xsl:with-param name="count" select="$max_c - count(div[#class='c'])" />
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="AddC">
<xsl:param name="count" />
<xsl:if test="$count > 0">
<div class="c">ccc
</div>
<xsl:call-template name="AddC">
<xsl:with-param name="count" select="$count - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The output is the following:
<html>
<body>
<div>
<div class="b">bbb</div>
<div class="c">ccc1
<div class="d">ddd11
<div class="e">eee11</div>
<div class="f">fff11
<div class="g">ggg111</div>
<div class="g">ggg112</div>
<div class="g">ggg113</div>
<div class="g">ggg114</div>
<div class="g">ggg115</div>
<div class="g">ggg116</div>
</div>
</div>
<div class="d">ddd12
<div class="e">eee12</div>
<div class="f">fff12
<div class="g">ggg121</div>
<div class="g">ggg122</div>
<div class="g">ggg123</div>
<div class="g">ggg124</div>
</div>
</div>
</div>
<div class="c">ccc2
<div class="d">ddd21
<div class="e">eee21</div>
<div class="f">fff21
<div class="g">ggg211</div>
<div class="g">ggg212</div>
<div class="g">ggg213</div>
<div class="g">ggg214</div>
<div class="g">ggg215</div>
</div>
</div>
</div>
<div class="c">ccc$count</div>
</div>
</body>
</html>
This is almost what I would like, with 2 exceptions:
The first div has lost its class="a" and its value aaa
The added div class="c" should have a value of ccc3, and not ccc$count
What am I doing wrong?
As usual I thank you in advance for your help.
The first div has lost its class="a" and its value aaa
To add the missing attributes and text content change the xslt:copy like the following:
<xsl:copy>
<xsl:apply-templates select="#* | div[#class='b'] | text()" />
<xsl:apply-templates select="div[#class='c']" />
The #*adds all attributes and the text() all text content.
The added div class="c" should have a value of ccc3, and not ccc$count
change the output for div c as:
<div class="c">
ccc<xsl:value-of select="$count"/>
</div>

apply-templates outputs content more times than expected

I'm new to XSLT and I can't understand why the root get processed twice (at least this is my interpretation of this output).
EDIT: (I'm using Saxon-HE with XSLT 2.0) but also tested with several online processes, getting always the same result.
XSLT file
<?xml version="1.0" encoding="UTF-8"?>
<!-- XResume.xsl: resume.xml ==> resume.xhtml -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="https://github.com/IME-SE8/XResume">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head>
<meta charset="utf-8" />
<meta lang="en" />
<meta name="description" content="Personal Resume and Portfolio" />
<title><xsl:value-of select="resume/personalInformation/name/attribute::shortForm" /> Website</title>
</head>
<body>
<xsl:apply-templates select="resume"/>
</body>
</html>
</xsl:template>
<xsl:template match="resume">
<div class="resume">
<div class="header">
<div class="name"><xsl:value-of select="personalInformation/name" /></div>
<div class="contacts">
<xsl:for-each select="personalInformation/contact">
<div class="contactInformation">
<p><xsl:value-of select="organization" /></p>
<p><xsl:value-of select="address" /></p>
<p><xsl:value-of select="phoneNumber" /></p>
<p><xsl:value-of select="email" /></p>
</div>
</xsl:for-each>
</div>
</div>
<div class="sections">
<xsl:apply-templates />
</div>
</div>
</xsl:template>
<xsl:template match="interests"></xsl:template>
<xsl:template match="education"></xsl:template>
<xsl:template match="skills"></xsl:template>
<xsl:template match="experiences"></xsl:template>
<xsl:template match="projects"></xsl:template>
<xsl:template match="awards"></xsl:template>
</xsl:stylesheet>
XML file
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl"
href="https://github.com/IME-SE8/XResume/master/XResume.xsl"?>
<resume
xmlns="https://github.com/IME-SE8/XResume"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/IME-SE8/XResume XResume.xsd">
<personalInformation>
<name first="John" last="Doe" shortForm="JD">John Doe</name>
<contact type="institutional">
<organization>StackOverflow Institute of Technology</organization>
<address>Internet</address>
<phoneNumber>+1 (666) 666-9999</phoneNumber>
<email>john#d.oe</email>
</contact>
</personalInformation>
<interests>
<interest>Q and A</interest>
<interest>XSLT</interest>
</interests>
<education></education>
<skills></skills>
<experiences></experiences>
<projects></projects>
<awards></awards>
</resume>
HTML output
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta lang="en">
<meta name="description" content="Personal Resume and Portfolio">
<title>JD Website</title>
</head>
<body>
<div class="resume">
<div class="header">
<div class="name">John Doe</div>
<div class="contacts">
<div class="contactInformation">
<p>StackOverflow Institute of Technology</p>
<p>Internet</p>
<p>+1 (666) 666-9999</p>
<p>john#d.oe</p>
</div>
</div>
</div>
<div class="sections">
John Doe
StackOverflow Institute of Technology
Internet
+1 (666) 666-9999
john#d.oe
</div>
</div>
</body>
</html>
(yes, with that amount of blank lines)
The output header div is perfectly fine, but inside the sections div that apply-templates renders all the information in the div header again but without the HTML tags.
Is there any XSLT processing detail am I missing? Does the template match sets the context in a way that the matched element is now considered a root or something like that?
The problem is here:
<div class="sections">
<xsl:apply-templates />
</div>
This applies templates to all child nodes of the current node (resume), including the personalInformation element.
As there is no matching template specified for personalInformation, the builtin XSLT templates are used by the XSLT processor and applying them results in outputting the concatenation of all descendent text-nodes of the personalInformation element.
Solution:
Replace:
<div class="sections">
<xsl:apply-templates />
</div>
with:
<div class="sections">
<xsl:apply-templates select="*[not(self::personalInformation)]" />
</div>
The result of the transformation now doesn't contain the noted problematic output:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta lang="en">
<meta name="description" content="Personal Resume and Portfolio">
<title>JD Website</title>
</head>
<body>
<div class="resume">
<div class="header">
<div class="name">John Doe</div>
<div class="contacts">
<div class="contactInformation">
<p>StackOverflow Institute of Technology</p>
<p>Internet</p>
<p>+1 (666) 666-9999</p>
<p>john#d.oe</p>
</div>
</div>
</div>
<div class="sections"></div>
</div>
</body>
</html>
You haven't supplied an expected output, so I will guess at your intended outcome. Here is an XSLT 2.0 solution. If you need XSLT 1.0, please comment, and I can add. But just remember that if your transform engine is the browser, you have no excuse not to use XSLT 2.0. (Refer Saxon CE).
XSLT 2.0 Solution
This XSLT 2.0 stylesheet ...
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:r="https://github.com/IME-SE8/XResume"
exclude-result-prefixes="r"
version="2.0">
<xsl:output method="html" version="5" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<html>
<head>
<meta lang="en" />
<meta name="description" content="Personal Resume and Portfolio" />
<title><xsl:value-of select="r:resume/r:personalInformation/r:name/#shortForm" /> Website</title>
</head>
<body>
<xsl:apply-templates select="r:resume"/>
</body>
</html>
</xsl:template>
<xsl:template match="r:resume">
<div class="resume">
<div class="header">
<div class="name"><xsl:value-of select="r:personalInformation/r:name" /></div>
<div class="contacts">
<xsl:apply-templates select="r:personalInformation/r:contact" />
</div>
</div>
<div class="sections">
<xsl:apply-templates select="* except r:personalInformation" />
</div>
</div>
</xsl:template>
<xsl:template match="r:contact">
<div class="contactInformation">
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template match="r:organization|r:address|r:phoneNumber|r:email">
<p><xsl:value-of select="." /></p>
</xsl:template>
<xsl:template match="r:education|r:skills|r:experiences|r:projects|r:awards">
<h2><xsl:value-of select="local-name()" /></h2>
<p><xsl:value-of select="." /></p>
</xsl:template>
<xsl:template match="r:interests">
<h2>interests</h2>
<ul>
<xsl:apply-templates />
</ul>
</xsl:template>
<xsl:template match="r:interest">
<li>
<xsl:value-of select="." />
</li>
</xsl:template>
<xsl:template match="*" />
</xsl:transform>
... when applied to this input document ...
<resume
xmlns="https://github.com/IME-SE8/XResume"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/IME-SE8/XResume XResume.xsd">
<personalInformation>
<name first="John" last="Doe" shortForm="JD">John Doe</name>
<contact type="institutional">
<organization>StackOverflow Institute of Technology</organization>
<address>Internet</address>
<phoneNumber>+1 (666) 666-9999</phoneNumber>
<email>john#d.oe</email>
</contact>
</personalInformation>
<interests>
<interest>Q and A</interest>
<interest>XSLT</interest>
</interests>
<education></education>
<skills></skills>
<experiences></experiences>
<projects></projects>
<awards></awards>
</resume>
... will yield this output html page ....
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta lang="en">
<meta name="description" content="Personal Resume and Portfolio">
<title>JD Website</title>
</head>
<body>
<div class="resume">
<div class="header">
<div class="name">John Doe</div>
<div class="contacts">
<div class="contactInformation">
<p>StackOverflow Institute of Technology</p>
<p>Internet</p>
<p>+1 (666) 666-9999</p>
<p>john#d.oe</p>
</div>
</div>
</div>
<div class="sections">
<h2>interests</h2>
<ul>
<li>Q and A</li>
<li>XSLT</li>
</ul>
<h2>education</h2>
<p></p>
<h2>skills</h2>
<p></p>
<h2>experiences</h2>
<p></p>
<h2>projects</h2>
<p></p>
<h2>awards</h2>
<p></p>
</div>
</div>
</body>
</html>
Explanation: Why were you getting root processed twice
In short because your <div class="sections"><xsl:apply-templates /></div> instruction did not specify a select attribute. The default selection applied, which was at that point the document root.
All the elements in your source document are in a namespace, but your stylesheet is written to process elements in no namespace. Welcome to the club, and join the 10m other people who have fallen into this trap. Essentially, you resume elements don't match the match="resume" template, so the default template kicks in, and this outputs the raw text with no tags. For the solution, search on "XSLT default namespace" and choose any one of about 1000 answers.
On re-reading, I see that you've used xpath-default-namespace="https://github.com/IME-SE8/XResume", which should fix the problem if you are using an XSLT 2.0 processor, or trigger an error if you're using an XSLT 1.0 processor. So it might be useful (actually, it's always useful) to tell us what processor you are using and how you are running it.

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