Problem with label call-template in XSLT - templates

I'm doing a series of XSL templates, but we did make them run on php-xsl. The problem I have is with the import and XSL inclucion other files, and palicacion of temples. I have the first file
<xsl:import href="forms.xsl"/>
<xsl:template match="/">
<a id="logo"><xsl:value-of select="web/general/title"/></a>
<xsl:call-template name="search" />
</xsl:template>
</xsl:stylesheet>
and I have forms.xsl file
<xsl:template match="search">
<form>
<label>search</label>
<input type="text" name="search" title="Search" />
<input type="botton" name="search"/>
</form>
</xsl:template>
but when I put on the run, I do not show anything. That's what I'm doing wrong?

In the forms.xsl, you need to change
<xsl:template match="search">
to
<xsl:template name="search">
Match will always match the xml expression, whereas name explicitly gives a name to a template.
If this doesn't work, please post the source xml and what you would like to see in the target.

Related

xslt fields grouped by their type

I have some data that i put in (image, title, text). I ahve 3 different elements in my xslt for each of them:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udt="DotNetNuke/UserDefinedTable" exclude-result-prefixes="udt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<!--
This prefix is used to generate module specific query strings
Each querystring or form value that starts with udt_{ModuleId}_param
will be added as parameter starting with param
-->
<xsl:variable name="prefix_param">udt_<xsl:value-of select="//udt:Context/udt:ModuleId" />_param</xsl:variable>
<xsl:template match="udt:Data" mode="list">
<xsl:value-of select="udt:Image" disable-output-escaping="yes" />
<xsl:value-of select="udt:Title" disable-output-escaping="yes" />
<xsl:value-of select="udt:Text" disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="/udt:UserDefinedTable">
<xsl:variable name="currentData" select="udt:Data" />
<xsl:if test="$currentData">
<xsl:apply-templates select="$currentData" mode="list">
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template name="EditLink">
<xsl:if test="udt:EditLink">
<a href="{udt:EditLink}">
<img border="0" alt="edit" src="{//udt:Context/udt:ApplicationPath}/images/edit.gif" />
</a>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I want to fill these elements each into its own div group, so my end result would be something like this:
<div id="images">
<!--all images here-->
</div>
<div id="title">
<!--all titles here-->
</div>
<div id="text">
<!--all texts here-->
</div>
Can this be achieved by any kind of grouping or whats the right aproach?
The concept to use xsl:value-of for your 3 element types is wrong,
as this instruction copies only the content of these elements,
without XML markup.
Assuming that the only goal is to reorder (group) your elements,
and they are direct descendants of the current element (udt:Data),
the task can be done the following way:
<xsl:template match="udt:Data">
<xsl:copy>
<div id="images">
<xsl:copy-of select="udt:Image"/>
</div>
<div id="title">
<xsl:copy-of select="udt:Title"/>
</div>
<div id="text">
<xsl:copy-of select="udt:Text"/>
</div>
</xsl:copy>
</xsl:template>
Of course, this is only a template, not the whole script.
Note that e.g. if these elements were located also at "deeper" descendant levels,
all the above XPath expressions should be prececed with descendant::.
And remember about including in your script all namespaces, the script refers to.
They should be declared in stylesheet tag.

Grouping divs in rows (clarification needed)

I realize that you are really good at programming and that your answers are dependable.
Is it possible for you to assist me in resolving an issue I am having with my xslt code? I'm new to progamming so I would appreciate any assistance I can get.
Your solution in grouping 3 divs in a row is found at the link below, but I do not know how to apply it to my code. I am using Sitecore and I have a div block that corresponds to each page generated to produce metro-like blocks, 3 in a row. So far I generates the desired divs but does not put them three in a row. My code is found below.
XSLT How can I wrap each 3 elements by div?
I would appreciate any help I can get.
<?xml version="1.0" encoding="UTF-8"?>
<!--=============================================================
File: ServicesFeatureblocks.xslt
Created by: sitecore\admin
Created: 3/27/2013 11:50:57 AM
Copyright notice at bottom of file
==============================================================-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sc="http://www.sitecore.net/sc"
xmlns:dot="http://www.sitecore.net/dot"
exclude-result-prefixes="dot sc">
<!-- output directives -->
<xsl:output method="html" indent="no" encoding="UTF-8" />
<!-- parameters -->
<xsl:param name="lang" select="'en'"/>
<xsl:param name="id" select="''"/>
<xsl:param name="sc_item"/>
<xsl:param name="sc_currentitem"/>
<!-- variables -->
<!-- Uncomment one of the following lines if you need a "home" variable in you code -->
<xsl:variable name="Services" select="sc:item('/sitecore/content/home/Services',.)" />
<!--<xsl:variable name="home" select="/*/item[#key='content']/item[#key='home']" />-->
<!--<xsl:variable name="home" select="$sc_currentitem/ancestor-or-self::item[#template='site root']" />-->
<!-- entry point -->
<xsl:template match="*">
<xsl:apply-templates select="$sc_item" mode="main"/>
</xsl:template>
<!--==============================================================-->
<!-- main -->
<!--==============================================================-->
<xsl:variable name="group" select="3" />
<xsl:template match="/">
<xsl:apply-templates select="$sc_currentitem[position() mod $group = 1]" />
</xsl:template>
<xsl:template match="item" mode="inner">
<div class="block orange">
<xsl:value-of select="sc:fld('Title',.)" />
</div>
<item/>
</xsl:template>
<xsl:template match="item">
<div>
<xsl:apply-templates
select="./item|following-sibling::services/item[position() < $group]" mode="inner" />
</div>
</xsl:template>
</xsl:stylesheet>
If you can use a sublayout instead of xslt rendering, You can achieve your functionality easily using Listview with GroupTemplate
<asp:ListView ID="listview1" runat="server" GroupItemCount="3" GroupPlaceholderID="groupPlaceholder"
ItemPlaceholderID="itemPlaceholder">
<LayoutTemplate>
<div class="productsContent">
<asp:PlaceHolder ID="groupPlaceholder" runat="server"></asp:PlaceHolder>
</div>
</LayoutTemplate>
<GroupTemplate>
<div class="product-rows">
<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
</div>
</GroupTemplate>
<ItemTemplate>
<div class="products">
</div>
</ItemTemplate>
</asp:ListView>

how to call a template to edit a tei stylesheet

I'm trying to automatically make epubs with a list of names after the body section.. In order to do this, I'm changing the tei stylesheet.
First, I tryed to insert this code in the "to.xsl" file, inside the "profiles/default/epub" folder:
<xsl:template match="tei:body">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
<xsl:element name="back" namespace="http://www.tei-c.org/ns/1.0">
<xsl:element name="div" namespace="http://www.tei-c.org/ns/1.0">
<xsl:for-each select="//tei:rs[#type='luogo']">
<xsl:element name="p" namespace="http://www.tei-c.org/ns/1.0">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:template>
In this case the output shows the list of names before the body section.
Then I found the "bodyHook" template that you can see here, but it doesn't work (or I don't understand how to use it).
I tried to write something like this:
<xsl:param name="indiceNomi">
<back>
<div>
<xsl:for-each select="//tei:rs[#type='luogo']">
<p>
<xsl:value-of select="."/>
</p>
</xsl:for-each>
</div>
</back>
</xsl:param>
<xsl:template match="tei:body">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
<xsl:call-template name="bodyHook"/>
<xsl:with-param name="creaIndice" select="$indiceNomi"/>
</xsl:template>
But it is incorrect (seems that xsl:with-param can't be inside xsl:template, even if I saw some example like this).
So, if this is my input file, what kind of code I have to write?
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="file:/C:/Users/User/Desktop/prova2.xsl"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<teiHeader><fileDesc>
<titleStmt>
<title>AA</title>
</titleStmt>
<publicationStmt><p><!-- supply publication information --></p></publicationStmt>
<sourceDesc>
<bibl>AA</bibl>
</sourceDesc>
</fileDesc><profileDesc>
<langUsage>
<language ident="ita">AA</language>
<language ident="lat">AA</language>
</langUsage>
</profileDesc></teiHeader>
<text>
<body>
<div type="book" n="3" xml:id="L3">
<head>AA
</head>
<div type="capitolo" n="1" xml:id="L3-01">
<head>AA</head>
<p>AA
<pb n="200"/>textt<rs type="luogo">Genova</rs>texttex ttexttexttexttexttexttexttexttext<rs type="luogo">London</rs>exttextte<rs type="luogo">Paris</rs>
texttexttexttexttexttexttexttexttext<rs type="luogo">Tokyo</rs>xttexttexttexttexttexttexttext<rs type="luogo">New York</rs>
<rs type="luogo">Dublin</rs><rs type="luogo">Moscow</rs><rs type="luogo">Cairo</rs>texttexttexttexttexttexttexttexttexttexttexttexttexttexttext</p>
</div>
</div>
</body>
</text>
</TEI>
Thanks in advance, it will help me a lot to have some answer.
I think you've misunderstood somewhat how to customize the TEI XSLT behavior. You're not supposed to modify the predefined files. The top of this page gives a simple explanation. Basically the idea is that you would create your own XSLT file that imports the tei.xsl file, and add your own templates to your own XSLT file to customize the behavior. For example, to define a template to be inserted at the end of the <body> section, you would add something like this to your XSLT file:
<xsl:template name="bodyEndHook">
<back>
<div>
<xsl:for-each select="//tei:rs[#type='luogo']">
<p>
<xsl:value-of select="."/>
</p>
</xsl:for-each>
</div>
</back>
</xsl:template>
Presumably, the TEI transform automatically calls this template at the end of the <body>. The default behavior for bodyEndHook is to do nothing, but you can override that default behavior by adding your own templat.

Modify "on the fly" the portal column content tag's class

I need to modify "on the fly" a class name in portal-column-content tag, this is the html code rendered:
<div id="portal-column-content" class="cell width-9 position-1:4">
I want to replace only "width-9" with "width-12".
Any advice?
Thank's
Vito
Since you ask for advise, here is some:
Do not use a css class to signify anything concrete, let it signify intent.
The concrete implementation of the intent comes in the css. For instance, do not create a class named width-9, rather create one named portal-column-content. You can then make portal-column-content be width:9px, width:12em or whatever.
Doing a string-replace like this is not really a thing you would do with xslt.
Even though you could. Depending on your setup there are other, better ways.
If you can't/won't follow any of the above advise, try
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#class">
<xsl:attribute name="class">
<xsl:value-of select="substring-before(.,'width-9')"/>width-12<xsl:value-of select="substring-after(.,'width-9')"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
This XSLT 1.0 transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#id='portal-column-content']/#class">
<xsl:attribute name="class">
<xsl:value-of select=
"substring-before(concat(.,'width-9'), 'width-9')"/>
<xsl:value-of select="'width-12'"/>
<xsl:value-of select="substring-after(., 'width-9')"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the following sample XML document:
<html>
<div id="a" class="a"/>
<div id="b" class="b"/>
<div id="c" class="cell width-9 position-1:4"/>
<div id="portal-column-content" class="cell width-9 position-1:4"/>
<div id="d" class="d"/>
<div id="e" class="cell width-9 position-1:4"/>
</html>
produces the wanted, correct result (only replaced is the 'width-9' substring of the class attribute of any div that has id attribute with string value 'portal-column-content':
<html>
<div id="a" class="a"></div>
<div id="b" class="b"></div>
<div id="c" class="cell width-9 position-1:4"></div>
<div id="portal-column-content" class="cell width-12 position-1:4"></div>
<div id="d" class="d"></div>
<div id="e" class="cell width-9 position-1:4"></div>
</html>
Do note:
Only replaced is the 'width-9' substring of the class attribute of any div that has id attribute with string value 'portal-column-content'. Other div elements that have a different id attribute aren't affected.
The transformation correctly works with class attributes, whose string value doesn't contain 'width-9' -- compare with the other answer, whose XSLT solution in such case completely replaces the string value of the class attribute with 'width-12'.
Since you've tagged this with "diazo", the simplest solution is probably to use diazo rules. Just use a replace, before or after rule to copy content children of #portal-column-content to the theme children of a correctly classed #portal-column-content.
Use an "if" expression if it's to be done selectively.

Sorting by selectbox in XSLT

I have this selectbox on a site Im currently building and what I want to do, is sort a list of items displayed on the page by the value that's being selected.
The problem is that I got different kinds of data types, e.g. location and price.
If I want to sort on location, no problem it sorts perfectly on alphabetic order of the location names. But if I sort on the 'Low budget', which is from low to high in price, I have to add additional tags to the sort (data-type="number"). That works fine, but then the location and such aren't working anymore.
How to solve this to make it handle all kinds of different data types?
My XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:param name="url-filter" select="'recommended'" />
<xsl:template name="resort-list" match="data/resorts/entry">
<form name="sort-form" action="{$root}/resorts/" method="get">
<select name="filter" onChange="document.getElementById('sort-form').submit();">
<option value="">Sort By...</option>
<option value="recommended">Recommended</option>
<option value="location">Location</option>
<option value="prices-from">Low budget</option>
<option value="prices-till">High budget</option>
</select>
</form>
<xsl:for-each select="data/resorts/entry">
<!-- this is were I sort the items -->
<xsl:sort select="*[name() = $url-filter]" />
<a href="{$root}/koh-lipe-resorts/resort-view/{resort-name/#handle}">
<h3 class="resort-item-heading grey"><xsl:value-of select="resort-name"/></h3>
<p>
<xsl:call-template name="truncate">
<xsl:with-param name="value" select="resort-description" />
<xsl:with-param name="length" select="150" />
</xsl:call-template>
</p>
</a>
</xsl:for-each>
</xsl:template>
<xsl:include href="../utilities/master.xsl"/>
</xsl:stylesheet>
My XML:
<data>
<events />
<resorts>
<pagination total-entries="11" total-pages="2"
entries-per-page="10" current-page="1" />
<section id="9" handle="resorts">Resorts</section>
<entry id="114">
<price-from handle="1200">1200</price-from>
<price-till handle="1900">1900</price-till>
<recommended>No</recommended>
<lipe-green-aware-resort>No</lipe-green-aware-resort>
<name>Baja Resort</name>
<location>Sunrise Beach</location>
</entry>
</resorts>
</data>
This transformation correctly sorts for each possible parameter value: "recommended" or "price-from":
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="url-filter" select="'price-from'" />
<xsl:variable name="vSortOrder">
<xsl:choose>
<xsl:when test="$url-filter = 'price-from'">
<xsl:text>ascending</xsl:text>
</xsl:when>
<xsl:otherwise>descending</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="vSortType">
<xsl:choose>
<xsl:when test="$url-filter = 'price-from'">
<xsl:text>number</xsl:text>
</xsl:when>
<xsl:otherwise>text</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template name="resort-list" match="data/resorts">
<form name="sort-form" action="/*/resorts/" method="get">
<select name="filter" onChange="document.getElementById('sort-form').submit();">
<option value="">Sort By...</option>
<option value="recommended">Recommended</option>
<option value="location">Location</option>
<option value="prices-from">Low budget</option>
<option value="prices-till">High budget</option>
</select>
</form>
<xsl:for-each select="entry">
<!-- this is were I sort the items -->
<xsl:sort select="*[name() = $url-filter]"
data-type="{$vSortType}" order="{$vSortOrder}" />
<a href="/*/koh-lipe-resorts/resort-view/{resort-name/#handle}">
<h3 class="resort-item-heading grey"><xsl:value-of select="name"/></h3>
</a>
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>
</xsl:stylesheet>
With the this XML document (extending the provided with just one more entry):
<data>
<events />
<resorts>
<pagination total-entries="11" total-pages="2"
entries-per-page="10" current-page="1" />
<section id="9" handle="resorts">Resorts</section>
<entry id="114">
<price-from handle="1200">1400</price-from>
<price-till handle="1900">1900</price-till>
<recommended>No</recommended>
<lipe-green-aware-resort>No</lipe-green-aware-resort>
<name>Baja Resort</name>
<location>Sunrise Beach</location>
</entry>
<entry id="115">
<price-from handle="1500">1500</price-from>
<price-till handle="1700">1700</price-till>
<recommended>Yes</recommended>
<lipe-green-aware-resort>No</lipe-green-aware-resort>
<name>Blah-Blah Resort</name>
<location>Blah-Blah Beach</location>
</entry>
</resorts>
</data>
and with each of the two possible values of the $url-filter parameter, the correct results are produced sorted with the correct sort-key data type and in the correct sort order (ascending or descending).
Good question. Here's a way to do it:
Create a named template for your
inner <a> element, call it "link"
for example.
Create two named templates for your sorted for-each: "sort-by-alpha"
and "sort-by-number".
"sort-by-number" does a for-each, sorts by number, and calls the "link" template.
"sort-by-alpha" does a for-each, sorts (by alpha), and calls the "link" template.
In your outer template, outside of where you currently have for-each on data/resorts/entry, put a choose-when-test-otherwise that decides to call "sort-by-number" when the sort criterion is prices-from or prices-till; otherwise, it calls sort-by-alpha.
Does that make sense? Let me know if this doesn't do it for you.