How can these XSLT documents be DRY-ed - xslt

I have made two pages and now I wonder if I can DRY them.
Here the XSLT:
Frontpage: http://pastebin.com/yuZL913W
dagboek-page: http://pastebin.com/6FGYvpvf (Edited)
Roelof
Sorry one of the links is wrong.
I edited this.
My question is how to DRY these so I can reuse parts. Only the <div id="posts"> is different.
I think I understand the fill in the blanks but it is one big xslt file. Is this possible without named templates and call-templates

Here is one way -- what I call "Fill-in-the-blanks" to separate content from processing and to parameterize processing:
Rendering file (c:/temp/delete/nc3.xml):
<html xmlns:gen="gen:gen">
<gen:data from="params" mode="top"/>
<body >
<div id="outer">
<div id="container">
<div id="search">
<form method="get" id="searchform" action="http://www.notepadchaos.com/">
<input type="text" value="" name="s" id="s" class="txtField" />
<input type="submit" id="searchsubmit" class="btnSearch" value="Find It " />
</form>
</div>
<div id="title">
<h2>Tamara Wobben</h2>
</div>
</div>
<div id="content">
<div class="col01">
<div class="post">
<h3> <gen:data from="entry/title"/> </h3>
<div class="post-inner">
<gen:data from="section/entry/tekst" />
</div></div></div>
<div class="side-columns">
<div class="col02">
<div class="pages">
<!-- hier komen de losse pagina's -->
</div>
<div class="pages-bottom"></div>
<div class="categories-upper"></div>
<div class="categories">
<!-- hier komt het menu -->
</div>
<div class="categories-btm"></div>
</div>
<div class ="col03">
<div class="recent-post" >
<!-- hier komen de recente posts -->
</div>
<div class="postit-bottom"></div>
</div>
</div>
<br style="clear:both" />
</div>
<gen:data from="params" mode="down"/>
</div>
</body>
</html>
Data file (c:/temp/delete/data.xml):
<data>
<params>
<today>2011-12-29</today>
<current-time>22:17</current-time>
<this-year>2011</this-year>
<this-month>12</this-month>
<this-day>29</this-day>
<timezone>+01:00</timezone>
<website-name>Tamara Wobben</website-name>
<page-title>frontpage</page-title>
<root>http://test.tamarawobben.nl</root>
<workspace>http://test.tamarawobben.nl/workspace</workspace>
<root-page>frontpage</root-page>
<current-page>frontpage</current-page>
<current-page-id>6</current-page-id>
<current-path>/?debug=xml</current-path>
<parent-path>/</parent-path>
<current-url>http://test.tamarawobben.nl/?debug=xml</current-url>
<upload-limit>2097152</upload-limit>
<symphony-version>2.2.5</symphony-version>
<cookie-username>xxxx</cookie-username>
<cookie-pass>xxxxx</cookie-pass>
<site-mode>live</site-mode>
</params>
<events />
<image>
<section id="7" handle="images">Images</section>
<entry id="13">
<image size="22 KB" path="/images" type="image/jpeg">
<filename>img_5874.jpg</filename>
<meta creation="2011-12-19T18:40:04+01:00" width="400" height="267" />
</image>
</entry>
</image>
<recent-posts>
<section id="9" handle="dagboek">Dagboek</section>
<entry id="15">
<datum time="00:00" weekday="2">2005-02-22</datum>
<titel handle="7-weken-echo">7 weken echo</titel>
</entry>
</recent-posts>
<section>
<section id="6" handle="sections">Sections</section>
<entry id="12">
<title handle="even-voorstellen">Even Voorstellen</title>
<tekst><p>FLOAT : img_5874.jpg</p> 55 56<p>Naam : Tamara Wobben<br /> 57Geboorte gewicht : 2000 gram<br /> 58Geboorte lengte : 44 cm.<br /> 59Geboortedatum : 1 september 2005 </p>
</tekst>
</entry>
</section>
</data>
XSLT code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gen="gen:gen" exclude-result-prefixes="gen">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pFormPath" select=
"'file:///c:/temp/delete/nc3.xml'"/>
<xsl:param name="pDataPath" select=
"'file:///c:/temp/delete/data.xml'"/>
<xsl:variable name="vFormDoc" select="document($pFormPath)"/>
<xsl:variable name="vDataDoc" select="document($pDataPath)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$vFormDoc/*"/>
</xsl:template>
<xsl:template match=
"gen:data
[#from='params'
and
#mode='top'
]">
<!-- Use $vDataDoc to populate this -->
T O P S T U F
</xsl:template>
<xsl:template match=
"gen:data[#from='entry/Title']">
<!-- Use $vDataDoc to populate this -->
E N T R Y T I T L E
</xsl:template>
<xsl:template match=
"gen:data[#from='section/entry/tekst']">
<!-- Use $vDataDoc to populate this -->
S E C T I O N E N T R Y T E X T
</xsl:template>
<xsl:template match=
"gen:data
[#from='params'
and
#mode='down'
]">
<!-- Use $vDataDoc to populate this -->
D O W N S T U F
</xsl:template>
</xsl:stylesheet>
Source XML file (not used):
<t/>
When the above transformation is performed on any XML file (not used), the rendering file is populated with data from the data file. The templates that process the placeholder gen:data elements, are dummy but still demonstrate how this processing works.
The result of the processing:
<html xmlns:gen="gen:gen">
T O P S T U F
<body>
<div id="outer">
<div id="container">
<div id="search">
<form method="get" id="searchform" action="http://www.notepadchaos.com/"><input type="text" value="" name="s" id="s" class="txtField"><input type="submit" id="searchsubmit" class="btnSearch" value="Find It "></form>
</div>
<div id="title">
<h2>Tamara Wobben</h2>
</div>
</div>
<div id="content">
<div class="col01">
<div class="post">
<h3>
<gen:data from="entry/title"></gen:data>
</h3>
<div class="post-inner">
S E C T I O N E N T R Y T E X T
</div>
</div>
</div>
<div class="side-columns">
<div class="col02">
<div class="pages">
<!-- hier komen de losse pagina's -->
</div>
<div class="pages-bottom"></div>
<div class="categories-upper"></div>
<div class="categories">
<!-- hier komt het menu -->
</div>
<div class="categories-btm"></div>
</div>
<div class="col03">
<div class="recent-post">
<!-- hier komen de recente posts -->
</div>
<div class="postit-bottom"></div>
</div>
</div><br style="clear:both"></div>
D O W N S T U F
</div>
</body>
</html>
Do note:
This code can populate any rendering document (path passed as an external parameter) using the data from any data document (again path passed as an external parameter). Thus it becomes possible to create different outputs/formats populated with different data.
The placeholders (gen:data elements) to be replaced with "live content" can have different format and semantics -- no limits to one's imagination.
Editors (non-XSLT experts) can work on one or more rendering documents independently from each other and from the XSLT developers.
A higher degree of reusability, flexibility and maintainability is achieved.

Related

Test for following sibling not having argument

Consider the following xml file:
<main>
<sub>
<div n="1"/>
<div n="2"/>
<div n="3"/>
<div n="-">
</sub>
<sub>
<div n="1"/>
<div n="2"/>
<div/>
</sub>
<sub>
<div n="1"/>
<div n="2"/>
<div n="-"/>
</sub>
</main>
I want to output only the value of the last #n that is a digit and is followed either by a div with no #n or one with #n = '-'. The following test in a template that matches divs outputs all #ns containing digits...
<xsl:if test="
matches(#n, '[0-9]') and
following-sibling::div[not(#n) or #n='-']
">
I also tried:
<xsl:if test="
matches(#n, '[0-9]') and
(not(following-sibling::div[#n]) or
following-sibling::div[#n='-'])
">
Am I missing something?

xsl loop with new name for template tag

I am trying to use a loop iteration in xslt. I want to loop through all the text with tei of "orgName", and generate a different popover-body for each one. I hope it would be something like (div class="Org-popover-body-1),(div class="Org-popover-body-2)... What should I put in ??? Thanks beforehand.
<xsl:template match="tei:orgName">
<xsl:for-each select="orgName">
<a class="orgName" id="orgNameinfo" data-toggle="popover-2" data-trigger="fcours" data-popover-content-2="#a2" data-placement="right">
<xsl:attribute name="href">
<xsl:text>#</xsl:text>
<xsl:value-of select="#key" />
</xsl:attribute>
</a>
<div id="a2" class="hidden">
<div class="popover-heading2">Orgnization Information <span style="float:right;cursor:pointer;" class="fa fa-times" data-toggle="popover"></span>
</div>
<div class="Org-popover-body-???">
</div>
</div>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
I think what you need are Attribute Value Templates, so you would write this...
<div class="Org-popover-body-{position()}">
You probably want to do this in the id of the hidden div to (to avoid multiple divs with the same id)
<div id="a{position()}" class="hidden">
And similarly in the data-popover-content-2 attribute
... data-popover-content-2="#a{position()}" ...

XSLT: How to place multiple level nodes in <ol> in place of xls:number format

I'm new to xsl and messing about with a sample template to try and figure things out.
I managed to get this far as per below snippets. Not sure if the way I'm applying the template for the different System.AreaPath is correct, but seems to work?
The one thing I'm struggling with right now is to use ol (or ol for Epic, ul for all siblings) and css, instead of the template sample putting every in a div and h{$level}.
I'm hoping this will also resolve the current issue of the number format - apply-template does not reset the count when applied twice as I have done here.
Any suggestions or samples will be appreciated as I'm not finding - or rather understanding correctly how to implement - the various search results and samples I have found. (for-each and when came up frequently)
I hope the above makes sense and that the code pasted is sufficient?
Thanks in advance!
- Jacques
xml: (edit: xml, not xlm)
<result executedDate="8/8/2017" executedBy="abc" email="abc#email.com">
<columns>
<System.Id name="ID" width="75" type="Integer"/>
<System.WorkItemType name="Work Item Type" width="75" type="String"/>
<System.Title name="Title" width="150" type="String"/>
<System.AreaPath name="Area Path" width="75" type="TreePath"/>
</columns>
<options>
...
</options>
<workitem id="1051" type="Epic" state="In Progress">
<System.Id>1051</System.Id>
<System.WorkItemType>Epic</System.WorkItemType>
<System.Title>Epic1</System.Title>
<System.AreaPath>Path1</System.AreaPath>
<workitem id="5411" type="Feature" state="Done">
<System.Id>5411</System.Id>
<System.WorkItemType>Feature</System.WorkItemType>
<System.Title>Feature1</System.Title>
<System.AreaPath>Path1</System.AreaPath>
<workitem id="5414" type="Product Backlog Item" state="Done">
<System.Id>5414</System.Id>
<System.WorkItemType>Product Backlog Item</System.WorkItemType>
<System.Title>Backlog Item 1</System.Title>
<System.AreaPath>Path1</System.AreaPath>
</workitem>
<workitem id="5418" type="Product Backlog Item" state="Done">
<System.Id>5418</System.Id>
<System.WorkItemType>Product Backlog Item</System.WorkItemType>
<System.Title>Backlog Item 2</System.Title>
<System.AreaPath>Path1</System.AreaPath>
</workitem>
</workitem>
</workitem>
<workitem id="1529" type="Epic" state="In Progress">
<System.Id>1529</System.Id>
<System.WorkItemType>Epic</System.WorkItemType>
<System.Title>Epic 2</System.Title>
<System.AreaPath>Path2</System.AreaPath>
<workitem id="3956" type="Feature" state="Done">
<System.Id>3956</System.Id>
<System.WorkItemType>Feature</System.WorkItemType>
<System.Title>Feature 2</System.Title>
<System.AreaPath>Path 2</System.AreaPath>
<workitem id="5955" type="Product Backlog Item" state="Done">
<System.Id>5955</System.Id>
<System.WorkItemType>Product Backlog Item</System.WorkItemType>
<System.Title>Backlog item 3</System.Title>
<System.AreaPath>Path2</System.AreaPath>
</workitem>
<workitem id="6667" type="Product Backlog Item" state="Done">
<System.Id>6667</System.Id>
<System.WorkItemType>Product Backlog Item</System.WorkItemType>
<System.Title>Backlog item 4</System.Title>
<System.AreaPath>Path2</System.AreaPath>
</workitem>
</workitem>
xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<h2>Section 1</h2>
<xsl:apply-templates select="/result /workitem[#type != 'Bug' and System.AreaPath='Path2']"/>
<p/>
<h2>Section 2</h2>
<xsl:apply-templates select="/result /workitem[#type != 'Bug' and System.AreaPath='Path1']"/>
</body>
</html>
</xsl:template>
<xsl:template match="//workitem">
<xsl:variable name="level" select="count(ancestor-or-self::*) "/>
<xsl:element name="h{$level}">
<xsl:number level="multiple" format="1. "/>
<xsl:value-of select="System.Title"/>
</xsl:element>
<div style="margin-left:15px;">
<xsl:apply-templates select="workitem"/>
</div>
</xsl:template>
html ouput:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html">
<meta charset="UTF-8">
</head>
<body>
<h2>Section 1</h2>
<h2>2. Epic 2</h2>
<div style="margin-left:15px;">
<h3>2.1. Feature 2</h3>
<div style="margin-left:15px;">
<h4>2.1.1. Backlog item 3</h4>
<div style="margin-left:15px;"></div>
<h4>2.1.2. Backlog item 4</h4>
<div style="margin-left:15px;"></div>
</div>
</div>
<p></p>
<h2>Section 2</h2>
<h2>1. Epic1</h2>
<div style="margin-left:15px;">
<h3>1.1. Feature1</h3>
<div style="margin-left:15px;">
<h4>1.1.1. Backlog item 1</h4>
<div style="margin-left:15px;"></div>
<h4>1.1.2. Backlog item 2</h4>
<div style="margin-left:15px;"></div>
</div>
</div>
Desired html output:
This is basesd on a current view in use that I'm trying to replicate. Might opt to not use the table later on, but the <ul> layout is what I'm after.
Also, the 'epic' node will likely not be used and can be excluded in the query generating the xml
<table>
<tr>
<td class=class1>Section 1</td> <!-- list all features from Path2 -->
</tr>
<tr>
<td>
<ul class=class2>
<li>Feature 3
<ul>
<li>Backlog item 5</li>
<li>Backlog item 6</li>
</ul>
</li>
<li>Feature 4
<ul>
<li>Backlog item 7</li>
<li>Backlog item 8</li>
</ul>
</li>
</ul>
</td>
</tr>
<tr>
<td class=class1>Section 2</td> <!-- list all features from Path1 -->
</tr>
<tr>
<td>
<ul class=class2>
<li>Feature1
<ul>
<li>Backlog item 1</li>
<li>Backlog item 2</li>
</ul>
</li>
<li>Feature 2
<ul>
<li>Backlog item 3</li>
<li>Backlog item 4</li>
</ul>
</li>
</ul>
</td>
</tr>
</table>
Your expected output is not clear. If you want a nested list, you could do simply:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/result">
<html>
<body>
<ul>
<xsl:apply-templates select="workitem[#type != 'Bug' and starts-with(System.AreaPath, 'Path')]"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="workitem">
<li>
<xsl:number level="multiple" format="1. "/>
<xsl:value-of select="System.Title"/>
</li>
<xsl:if test="workitem">
<ul>
<xsl:apply-templates select="workitem"/>
</ul>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
and get:
Result
<html>
<body>
<ul>
<li>1. Epic1</li>
<ul>
<li>1.1. Feature1</li>
<ul>
<li>1.1.1. Backlog Item 1</li>
<li>1.1.2. Backlog Item 2</li>
</ul>
</ul>
<li>2. Epic 2</li>
<ul>
<li>2.1. Feature 2</li>
<ul>
<li>2.1.1. Backlog item 3</li>
<li>2.1.2. Backlog item 4</li>
</ul>
</ul>
</ul>
</body>
</html>

XSL If Statement used for when Link is clicked

I have an RSS feed being pulled through XSLT on an .xsl file. I have a "Show" Link that when clicked displays a hidden DIV with an Iframe that has the source of the unique RSS Item's full page.
The issue is since this DIV is hidden it actually loads all the iframe's source pages when the page is first viewed and boggs down the loading time considerably.
What i want to do is only have the iframe load the source after the "Show" button is clicked. How can i invoke this with an XSLT If Statement?
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:user="urn:my-extension-lib:date">
<xsl:template match="/">
<xsl:for-each select="rss/channel/item">
<div style="margin-bottom: 30px;">
<div style="margin: 5px;">
<div style="font-weight: bold;">
<a href="{link}" target="_blank" style="font-size: 10pt;">
<xsl:value-of select="title" />
</a>
</div>
<div>
<xsl:value-of select="user:GetFormattedDate(pubDate,'MMM d, yyyy hh:mm tt')" />
</div>
</div>
<div style="padding-left:30px">
Show
</div>
<div style="margin: 20px 20px 20px 40px;display:none" id="{guid}">
<iframe width="685" height="400" scrolling="yes" frameborder="yes" src="{link}"></iframe>
</div>
</div>
</xsl:for-each>
</xsl:template>
What I think you need to do is initially load a 'blank' page for each IFRAME. For example, a page called blank.htm, that is empty. Also, you may want to give each IFRAME an ID tag, so you can easily access it with Javascript to change the source
<iframe id="iframe{guid}" width="685" height="400" scrolling="yes" frameborder="yes" src="blank.htm"/>
Then, you can code your javascript like so, to show the DIV, and change the source of the IFRAME to the correct page.
function test(id, link)
{
document.getElementById(id).style.display = 'block';
document.getElementById("iframe" + id).src = link;
}
Here's an example of the whole stylesheet for you
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>Test</title>
<script>
function test(id, link)
{
document.getElementById(id).style.display = 'block';
document.getElementById("iframe" + id).src = link;
}
</script>
</head>
<body>
<xsl:for-each select="rss/channel/item">
<div style="margin-bottom: 30px;">
<div style="margin: 5px;">
<div style="font-weight: bold;">
<a href="{link}" target="_blank" style="font-size: 10pt;">
<xsl:value-of select="title"/>
</a>
</div>
<div>
<xsl:value-of select="pubDate"/>
</div>
</div>
<div style="padding-left:30px">
Show
</div>
<div style="margin: 20px 20px 20px 40px;display:none" id="{guid}">
<iframe id="iframe{guid}" width="685" height="400" scrolling="yes" frameborder="yes" src="blank.htm"/>
</div>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

I'm trying to for loop through the sitecore templates instead of the items

Ok so this is my xslt for looping through the items of the home item, but I would like to be able to loop through the template... The reason for this is so that my xslt can be more specific instead of showing everything under the home item
<xsl:template match="*" mode="main">
<div id="aside">
<ul id="nav">
<xsl:for-each select="$home/descendant-or-self::item[position() <= 6]">
<li>
<sc:link>
<sc:text field="Title"></sc:text>
</sc:link>
</li>
</xsl:for-each>
</ul>
<div class="advertisement">
<sc:image field="Image"></sc:image>
</div>
</div>
</xsl:template>
From your xslt it seems you are talking about the navigation. Instead of looping through different templates I would create a specific Navigation template that has only one field called ShowInNavigation.
Then all your other templates will inherit this one and the navigation xslt will become simpler
<xsl:template match="*" mode="main">
<div id="aside">
<ul id="nav">
<xsl:for-each select="$home/descendant-or-self::item[sc:fld('ShowInNavigation') = '1']">
<li>
<sc:link>
<sc:text field="Title"></sc:text>
</sc:link>
</li>
</xsl:for-each>
</ul>
<div class="advertisement">
<sc:image field="Image"></sc:image>
</div>
</div>
</xsl:template>
Also don't use descendant-or-self::item in the navigation because as the site grows the navigation will become your bottleneck.
Better use $home/item[sc:fld('ShowInNavigation') = '1'] and then hardcode the home node above. So the xslt will become:
<xsl:template match="*" mode="main">
<div id="aside">
<ul id="nav">
<li>
<sc:link select="$home">
<sc:text field="Title"></sc:text>
</sc:link>
</li>
<xsl:for-each select="$home/item[sc:fld('ShowInNavigation') = '1']">
<li>
<sc:link>
<sc:text field="Title"></sc:text>
</sc:link>
</li>
</xsl:for-each>
</ul>
<div class="advertisement">
<sc:image field="Image"></sc:image>
</div>
</div>
</xsl:template>