Dynamic numbers of column in 1 row - xslt

i have number of categories that i want to separate it into rows, the number of category in a row will base on $catsInLine. The $catsInLine are digit from 1 to 12. Each category will be wrap by DIVs with class from span1 to span 12. And the categories will be wrap again with <div class="row-fluid"> for each row.
I tried below for hours and no luck getting the correct result.
<div class="row-fluid">
<xsl:variable name="catsInLine">
<xsl:value-of select="categories_in_line" />
</xsl:variable>
<xsl:variable name="column">
<xsl:value-of select="(12 div $catsInLine)" />
</xsl:variable>
<xsl:for-each select="categories/category">
<xsl:if test="position() mod $catsInLine = 1 or position() = 1">
<xsl:text disable-output-escaping="yes"><div class="row-fluid"></xsl:text>
</xsl:if>
<div class="span{$column}">
<xsl:call-template name="category" />
</div>
<xsl:if test="position() mod $catsInLine = 0 or position() = last()">
<xsl:text disable-output-escaping="yes"></div></xsl:text>
</xsl:if>
</xsl:for-each>
</div>
assume the $catsInLine is 2,the result i wish to get is
<div class="row-fluid">
<div class="span6">
<a>Category1</a>
</div>
<div class="span6">
<a>Category2</a>
</div>
</div>
<div class="row-fluid">
<div class="span6">
<a>Category3</a>
</div>
<div class="span6">
<a>Category4</a>
</div>
</div>
if the $catsInLine is 1, the result should be
<div class="row-fluid">
<div class="span12">
<a>Category1</a>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<a>Category2</a>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<a>Category3</a>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<a>Category4</a>
</div>
</div>

Please try this:
<xsl:apply-templates select="categories/category[position() mod $catsInLine = 1 or
$catsInLine = 1]"
mode="row" />
<!-- Separate template -->
<xsl:template match="category" mode="row">
<div class="row">
<xsl:apply-templates
select=". | following-sibling::category[position() < $catsInLine]" />
</div>
</xsl:template>

Related

Using XSLT create href to id based to attribute

I want to create a bootstrap accordion menu using xslt and read data from xml file. I have this xslt
<xsl:template match="/Settings">
<xsl:for-each select="Area">
<div class="panel-group configuration-menu-style" id="Menu">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#Menu" href="#{#Caption}">
<xsl:value-of select="#Caption"/>
</a>
</h4>
</div>
<div id="{#Caption}" class="panel-collapse collapse in">
<div class="panel-body custom-padding">
<table class="table">
<xsl:for-each select="Category">
<tr>
<td class="configuration-submenu-style">
<xsl:value-of select="#Caption"/>
</td>
</tr>
</xsl:for-each>
</table>
</div>
</div>
</div>
</div>
</xsl:for-each>
In this line
<div id="{#Caption}" class="panel-collapse collapse in">
i give id based to attribute and works. Using developer tools in browser i can see that has id="MENU OPTION2" The problem is in this line
<a data-toggle="collapse" data-parent="#Menu" href="#{#Caption}">
<xsl:value-of select="#Caption"/>
</a>
Using developer tools in browser i can see that this element has href="#MENU%20OPTION2
So... how can remove %20 from href?
SOLUTION
<a data-toggle="collapse" data-parent="#Menu" href="#{position()}">
<div id="{position()}" class="panel-collapse collapse in">
BECAUSE 'id="MENU OPTION2" is not valid as id should not contain space'
id="MENU OPTION2" is not valid as id should not contain spaces
Just have a look at this:
What are valid values for the id attribute in HTML?
So I suggest you use "MENU_OPTION2" or "MENU-OPTION2" as there would be no difference when urlencoding those strings.
-- EDIT --
By the way, I just remembered that I already worked on this kind of subject long time ago... http://xul.ccoste.fr/
And if you have a look as my XSLT file http://xul.ccoste.fr/xul-bootstrap.xsl, I used generate-id() to be sure that there would never be any conflict between IDs.
<xsl:template match="tabs">
<ul class="nav nav-tabs">
<xsl:for-each select="tab">
<li>
<xsl:if test="position() = 1">
<xsl:attribute name="class"><xsl:text>active</xsl:text></xsl:attribute>
</xsl:if>
<a data-toggle="tab" href="#{generate-id(../..)}-{position()}">
<xsl:value-of select="#label" />
</a>
</li>
</xsl:for-each>
</ul>

XSLT: Replacing div with script on multiple levels

I am trying to replace certain div-tags with script-tags within any level.
The code within the div that is set to display none is what I need (discard the two outer divs), and the divs within that code that has a class of "is-script" must be replaced with script, while keeping its attributes and nodes.
Some examples of how the code can look:
<div data-type="embed">
<div style="display:none;">
<div class="is-script" src="http://example.js"></div>
</div>
</div>
<div data-type="embed">
<div style="display:none;">
<div class="is-script" src="http://example1.js"></div>
<div class="is-script" src="http://example2.js"></div>
</div>
</div>
<div data-type="embed">
<div style="display:none;">
<div>
<div class="is-script" src="http://example.js"></div>
</div>
</div>
</div>
<div data-type="embed">
<div style="display:none;">
<div>
<div class="is-script" src="http://example1.js"></div>
<div class="is-script" src="http://example2.js"></div>
</div>
</div>
</div>
<div data-type="embed">
<div style="display:none;">
<div>
<div class="is-script" src="http://example1.js"></div>
<div class="is-script">some inline javascript</div>
</div>
</div>
</div>
<div data-type="embed">
<div style="display:none;">
<iframe src="http://example.html" width="100%" height="400px"></iframe>
</div>
</div>
The actual json that the xsl is parsing:
<div data-type=\"embed\" style=\"width:545px;height:200px;background-color:#ccc;\">HTML EMBED
<div style=\"display:none;\">
<div class=\"is-script\">console.log(\"test1\");</div>
</div>
</div>
<div data-type=\"embed\" style=\"width:545px;height:200px;background-color:#ccc;\">HTML EMBED
<div style=\"display:none;\">
<div>
<div class=\"is-script\">console.log(\"test2\");</div>
</div>
</div>
</div>
<div data-type=\"embed\" style=\"width:545px;height:200px;background-color:#ccc;\">HTML EMBED
<div style=\"display:none;\">
<div class=\"is-script\" src=\"example.js\"></div>
</div>
</div>
<div data-type=\"embed\" style=\"width:545px;height:200px;background-color:#ccc;\">HTML EMBED
<div style=\"display:none;\">
<div>
<div class=\"is-script\" src=\"example.js\"></div>
</div>
</div>
</div>
<div data-type=\"embed\" style=\"width:545px;height:200px;background-color:#ccc;\">HTML EMBED
<div style=\"display:none;\">
<div>
<div class=\"is-script\" src=\"example1.js\"></div>
<div class=\"is-script\" src=\"example2.js\"></div>
<div class=\"is-script\" src=\"example3.js\"></div>
</div>
</div>
</div>
Wanted result:
<script class="is-script" src="http://example.js"></script>
<script class="is-script" src="http://example1.js"></script>
<script class="is-script" src="http://example2.js"></script>
<div>
<script class="is-script" src="http://example.js"></script>
</div>
<div>
<script class="is-script" src="http://example1.js"></script>
<script class="is-script" src="http://example2.js"></script>
</div>
<div>
<script class="is-script" src="http://example1.js"></script>
<script class="is-script">some inline javascript</script>
</div>
<iframe src="http://example.html" width="100%" height="400px"></iframe>
Current result:
<script class="was-script-tag">console.log("test1");</script>
<div>
<div class="was-script-tag">console.log("test2");</div>
</div>
<script class="was-script-tag" src="/templates/v1/js/sticky_article_v7.js?v0"></script>
<div>
<div class="was-script-tag" src="/templates/v1/js/sticky_article_v7.js?v1"></div>
</div>
<div>
<div class="was-script-tag" src="/templates/v1/js/sticky_article_v7.js?v2"></div>
<div class="was-script-tag" src="/templates/v1/js/sticky_article_v7.js?v2"></div>
<div class="was-script-tag" src="/templates/v1/js/sticky_article_v7.js?v2"></div>
</div>
My xsl:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#data-type='embed' or parent::div[#data-type='embed']]">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="div[#class='is-script']">
<script>
<xsl:apply-templates select="#*|node()"/>
</script>
</xsl:template>
</xsl:stylesheet>
So basically remove two outer divs, and keep everyting inside as is, except divs with class of "is-script" which must be renamed to script. The two outer divs will always be the same.
I have a basic understanding of xsl, but this is something I just can't make work.
Using xslt 2.
You could possibly start off with the identity template, which will copy all existing nodes without change
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
Then, to ignore the "outer two divs" you can add an overriding template like so:
<xsl:template match="div[#data-type='embed' or parent::div[#data-type='embed']]">
<xsl:apply-templates />
</xsl:template>
This ignores div elements with a data-type of embed, or its immediate child div.
Then to change the "is-script" divs to script elements you can add another template
<xsl:template match="div[#class='is-script']">
<script>
<xsl:apply-templates select="#*|node()"/>
</script>
</xsl:template>
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#data-type='embed' or parent::div[#data-type='embed']]">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="div[#class='is-script']">
<script>
<xsl:apply-templates select="#*|node()"/>
</script>
</xsl:template>
</xsl:stylesheet>

Using XSLT for setting up a jssor gallery through a bunch of img tags

I have this XML document:
<?xml version='1.0' encoding='UTF-8'?>
<content>
<text>
<img src='path/01.jpg'/>
<img src='path/02.jpg'/>
<img src='path/03.jpg'/>
</text>
</content>
I would like to transform it in the HTML struct that the jssor gallery requires. This is what I want:
<div class='gallery'>
<div data-u='loading' class='loading'>
<div></div>
<div></div>
</div>
<div data-u='slides' class='slides'>
<!-- each img tag will be transformed in to this. The rest of the html is just a fixed structure -->
<div>
<img data-u='image' src='path/01.jpg' />
<img data-u='thumb' src='path/01.jpg' />
</div>
<div>
<img data-u='image' src='path/02.jpg' />
<img data-u='thumb' src='path/02.jpg' />
</div>
<div>
<img data-u='image' src='path/03.jpg' />
<img data-u='thumb' src='path/03.jpg' />
</div>
</div>
<span data-u='arrowleft' class='arrowleft'></span>
<span data-u='arrowright' class='arrowright'></span>
<div data-u='thumbnavigator' class='thumbnavigator'>
<div data-u='slides' class='slides'>
<div data-u='prototype' class='p'>
<div class='w'>
<div data-u='thumbnailtemplate' class='t'></div>
</div>
<div class='c'></div>
</div>
</div>
</div>
</div>
This is what I'm doing in XSLT:
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tpl='http://www.weblight.com.br/2015/XSL/Template'>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="content">
<div class='jssor_component galeria'>
<div data-u='loading' class='loading'>
<div><xsl:comment> </xsl:comment></div>
<div><xsl:comment> </xsl:comment></div>
</div>
<div data-u='slides' class='slides'>
<xsl:for-each select='text/img'>
<div>
<img data-u='image' src='{#src}'/>
<img data-u='thumb' src='{#src}'/>
</div>
</xsl:for-each>
</div>
<span data-u='arrowleft' class='arrowleft'><xsl:comment> </xsl:comment></span>
<span data-u='arrowright' class='arrowright'><xsl:comment> </xsl:comment></span>
<div data-u='thumbnavigator' class='thumbnavigator'>
<div data-u='slides' class='slides'>
<div data-u='prototype' class='p'>
<div class='w'>
<div data-u='thumbnailtemplate' class='t'></div>
</div>
<div class='c'><xsl:comment> </xsl:comment></div>
</div>
</div>
</div>
</div>
</xsl:template>
</xsl:transform>
But this is what I'm getting
<div class="jssor_component galeria">
<div data-u="loading" class="loading">
<div></div>
<div></div>
</div>
<div data-u="slides" class="slides"></div>
<span data-u="arrowleft" class="arrowleft"></span>
<span data-u="arrowright" class="arrowright"></span>
<div data-u="thumbnavigator" class="thumbnavigator">
<div data-u="slides" class="slides">
<div data-u="prototype" class="p">
<div class="w">
<div data-u="thumbnailtemplate" class="t" />
</div>
<div class="c"></div>
</div>
</div>
</div>
</div>
Seems to me like for-each not works like in thought, because the slide div is empty :/
After adding
<xsl:output method="xml" indent="yes"/>
as a child of the xsl:transform element in your XSLT so that the output XML will be readable, I do get the following output XML
<?xml version="1.0" encoding="UTF-8"?>
<div xmlns:tpl="http://www.weblight.com.br/2015/XSL/Template"
class="jssor_component galeria">
<div data-u="loading" class="loading">
<div><!----></div>
<div><!----></div>
</div>
<div data-u="slides" class="slides">
<div>
<img data-u="image" src="path/01.jpg"/>
<img data-u="thumb" src="path/01.jpg"/>
</div>
<div>
<img data-u="image" src="path/02.jpg"/>
<img data-u="thumb" src="path/02.jpg"/>
</div>
<div>
<img data-u="image" src="path/03.jpg"/>
<img data-u="thumb" src="path/03.jpg"/>
</div>
</div>
<span data-u="arrowleft" class="arrowleft"><!----></span>
<span data-u="arrowright" class="arrowright"><!----></span>
<div data-u="thumbnavigator" class="thumbnavigator">
<div data-u="slides" class="slides">
<div data-u="prototype" class="p">
<div class="w">
<div data-u="thumbnailtemplate" class="t"/>
</div>
<div class="c"><!----></div>
</div>
</div>
</div>
</div>
Which looks a lot like what you expected.
I see no way (analytically or empirically) that you could get XML output containing an empty data-u="slides" div as you indicated:
<div data-u="slides" class="slides"></div>
Surely
<xsl:for-each select='text/img'>
should be
<xsl:for-each select='div/img'>

XSLT transform cross placed tags

I'm new to XSLT and I need to transform cross placed tags like:
<tabbable>
<tab name="tabname1"><content1></content1></tab>
<tab name="tabname2"><content2></content2></tab>
<tab name="tabname3"><content3></content3></tab>
</tabbable>
transform to:
<div>
<ul>
<li>tabname1</li>
<li>tabname2</li>
<li>tabname3</li>
</ul>
<div class="baltab">
<div><transformed-content1/></div>
<div><transformed-content2/></div>
<div><transformed-content3/></div>
</div>
</div>
Unfortunately I can't find detailed tutorials for XSLT.
The solution is simplest as i first think:
Only needs two for-each cycle, with right element selected:
input:
<?xml version="1.0" encoding="ISO-8859-1"?>
<tabbedpane>
<tab text="tablabel1">
<label text="tabcontent1"/>
</tab>
<tab text="tablabel2">
<label text="tabcontent2"/>
</tab>
<tab text="tablable3">
<label text="tabcontent3"/>
</tab>
the transform xml:
<xsl:template match="tabbedpane">
<div class="LFT tabbable">
<ul class="nav nav-tabs">
<xsl:for-each select="tab">
<li class="tab_label">
<xsl:value-of select="#text"/>
</li>
</xsl:for-each>
</ul>
<div class="tabs_holder">
<xsl:for-each select="tab">
<div class="single_tab">
<xsl:apply-templates/>
</div>
</xsl:for-each>
</div>
</div>
</xsl:template>
<xsl:template match="label">
<h6>
<xsl:if test="#id">
<xsl:attribute name="id">
<xsl:value-of select="#id" />
</xsl:attribute>
</xsl:if>
<xsl:value-of select="#text"/>
</h6>
</xsl:template>
and the result is:
<div class="LFT tabbable">
<ul class="nav nav-tabs">
<li class="tab_label">tablabel1</li>
<li class="tab_label">tablabel2</li>
<li class="tab_label">tablable3</li>
</ul>
<div class="tabs_holder">
<div class="single_tab">
<h6>tabcontent1</h6>
</div>
<div class="single_tab">
<h6>tabcontent2</h6>
</div>
<div class="single_tab">
<h6>tabcontent3</h6>
</div>
</div>
</div>
As i needed.

Unusual Template Behavior with XSL

Experiencing some very odd behavior with, what should be, a very simple use of XSL and XSLT.
Here's a code sample.
<xsl:template match="check">
<div class="check">
<xsl:apply-templates mode="check">
<xsl:with-param name="checkName">testVariable</xsl:with-param>
</xsl:apple-templates>
</div>
</xsl:template>
The template called above
<xsl:template match="option" mode="check">
<xsl:param name="checkName" />
<div class="option">
<input type="checkbox">
</input>
<label>
testText
</label>
</div>
</xsl:template>
Pretty simple right?
It should, for each instance of a instance in the XML create a checkbox in a with a hard coded label.
However, what I'm getting is
<div class="check"></div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
<div class="check"></div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
<div class="option>Checkbox stuff here</div>
Here's some sample XML
<check><option key="1"/><option key="0"/><option
key="0"/><option key="0"/><option
key="0"/></check>
Anyone know what's going on? :D
The problem is either in the XML-document/code you haven't shown to us or, less likely, you may be using a buggy XSLT processor.
This transformation (Your code wrapped within an <xsl:stylesheet>):
<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="check">
<div class="check">
<xsl:apply-templates mode="check">
<xsl:with-param name="checkName">testVariable</xsl:with-param>
</xsl:apply-templates>
</div>
</xsl:template>
<xsl:template match="option" mode="check">
<xsl:param name="checkName" />
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<check>
<option key="1"/>
<option key="0"/>
<option key="0"/>
<option key="0"/>
<option key="0"/>
</check>
produces the wanted, correct result:
<div class="check">
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
<div class="option">
<input type="checkbox"></input>
<label>testText</label>
</div>
</div>
I have verified that the transformation produces identical results when run with:
Saxon 6.5.4
MSXML3, MSXML4, MSXML6
.NET XslCompiledTransform and XslTransform
Saxon 9.1.05
AltovaXML (XML-SPY)
XQSharp