Needs some help. In umbraco I have my tree like this
-First
- page 1
- page 2
- page 3
- page 4
- page 5
- page 6
- page 7
- page 8
- page 9
- page 10
- page 11
- page 12...
looping all the pages i filter them.
So I apply my xslt only to pages 4,7,10
position() will give me 4,7,10
How can I count the number of pages i walked through? (in this example 3)
Here's my xslt:
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant-or-self::* [#isDoc][#level=2]"/>
<xsl:template match="/">
<xsl:for-each select="$articles">
<xsl:if test="./* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage']">
...some html construction...
</xsl:if>
</xsl:for-each>
</xsl:template>
Thank you for your help.
Benjamin
PS: found those link that helped me to build the pagination but my counter isn't resolved
first link
second link
you can count the total number of pages you walk through like this:
count($articles/* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage'])
If you would like to have current 'count' inside your loop, you should change your xsl like this:
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant-or-self::* [#isDoc][#level=2]"/>
<xsl:template match="/">
<xsl:variable name="articlesToLoop" select="$articles//* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='myfilteredpage']" />
<xsl:for-each select="$articlesToLoop">
Current count: <xsl:value-of select="position()" />
- <xsl:value-of select="#nodeName" />
</xsl:for-each>
</xsl:template>
I've tried the counter you give... The counter show 0 when it needs to show 2.
I've found another behaviour of my xsl that is not clear. Only when my page as at least 1 child publish it shows me the page.
Here is my xslt code
<xsl:param name="currentPage"/>
<xsl:variable name="root" select="$currentPage/ancestor-or-self::* [#isDoc][last()]"/>
<xsl:variable name="articles" select="$root/descendant::* [#isDoc][#level=2]"/>
<xsl:variable name="NumberOfCharactersToShow" select="number(400)"/>
<xsl:template match="/">
<!-- start writing XSLT -->
<xsl:variable name="counter" select="count($articles//* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='Article'])" />
<xsl:value-of select="$counter" />
<xsl:for-each select="$articles">
<xsl:variable name="article" select="* [#isDoc and string(umbracoNaviHide)!='1' and local-name(current())='Article']" />
<xsl:if test="$article">
<xsl:call-template name="article" />
<!--<xsl:for-each select="current()/descendant::* [#isDoc]">
<xsl:call-template name="article" />
</xsl:for-each>-->
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="article">
<xsl:variable name="text" select="umbraco.library:StripHtml(umbraco.library:TruncateString(bodyText,$NumberOfCharactersToShow,'...'))"/>
<!--article-->
<div class="article border border-radius border-shadow">
<div class="atitle">
<p><xsl:value-of select="title" /></p>
</div>
<div class="atext">
<p><xsl:value-of select="$text" /></p>
</div>
</div>
</xsl:template>
Try to explain. Here is my example tree
-first page
-page
-article1 (published)
-article2 (unpublished)
-article3 (unpublished)
-page
-page
-page
-article4 (published)
-page
-article5 (published)
-article6 (published)
-article7 (unpublished)
-page...
actually my code will create only article5 (the children (article6,7) creation is in xslt comments)
But as you can see article1 and article4 are not created...I don't understand why...
Thanks for your help.
Benjamin
Related
With the following XML
<para>Refer to Table 3 and Figure <grphcref refid="apm00-02-02-000018" shownow="0">6</grphcref>
for the door dimensions and clearances.</para>
and this XSL:
<xsl:template match="prcitem">
<xsl:for-each select="para">
<p>
<xsl:value-of select="." />
<xsl:apply-templates select="./grphcref" />
</p>
</xsl:for-each>
<xsl:apply-templates select="grphcref" />
<xsl:apply-templates select="table" />
<xsl:apply-templates select="unlist" />
</xsl:template>
<xsl:template match="grphcref">
<xsl:variable name="gotoimg" select="concat('#',#refid)"/>
<a href="{$gotoimg}" >
<xsl:value-of select="." /> - <xsl:value-of select="#refid" /> </a>
</xsl:template>
I get:
<p>Refer to Table 3 and Figure 6 for the door dimensions and clearances.
6 - apm00-02-02-000018
when I expected:
<p>Refer to Table 3 and Figure 6 - apm00-02-02-000018
for the door dimensions and clearances.
Can anyone offer guidance as to where I went wrong?
thx
If a para element is supposed to be transformed to a p element then in my view the "natural" way in XSLT is a template
<xsl:template match="para">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
If any other elements need special treatment add a template e.g.
<xsl:template match="grphcref">
<xsl:variable name="gotoimg" select="concat('#',#refid)"/>
<a href="{$gotoimg}" >
<xsl:value-of select="." /> - <xsl:value-of select="#refid" /> </a>
</xsl:template>
Text nodes are copied through to the result by the built-in templates.
The input sample doesn't explain why you mix template matching and for-each and why or whether you need xsl:apply-templates with any particularly selected nodes; as long as the input order should be preserved a simple processing of all child nodes with <xsl:apply-templates/> should suffice.
I have difficulties to write a template that generates a breadcrumb trial out of a node structure. It is not working correctly up to now, there is some flaw in my thinking how it should walk the item path.
Consider the following page structure:
<!-- ===== SITE PAGE STRUCTURE ===================================== -->
<index>
<item section="home" id="index"></item>
<item section="service" id="index">
<item id="content-management-systems">
<item id="p1-1"/>
<item id="p1-2"/>
<item id="p1-3"/>
</item>
<item id="online-stores"></item>
<item id="search-engines-and-ir"></item>
<item id="web-applications"></item>
</item>
<item section="solutions" id="index">
<item id="document-clustering"></item>
</item>
<item section="company" id="index">
<item section="company" id="about"></item>
<item section="company" id="philosophy" ></item>
...
</item>
...
</item>
This site index represents a site-structure of xml content pages in its hierarchy (consider it to be a menu). It contains of sections, that represent the site sections just as home, company, service, solutions, etc. These sections can contain sub-sections with pages, or just regular content pages. A content page (its xml contents such as title, text content, etc) is identified by the #id attribute in the item tree. The #id attribute mainly is used to fetch the content of the entire page that will be rendered to html.
The breadcrumb template uses the item node #id attribute to get the title of the page (which will be shown in the breadcrumb trail).
I try to implement the following template that walks the tree by checking the target section attribute #section and the target page attribute #id in the tree. I expect it to walk the axis down until the target item_target is found by comparing the ancestors #section attribute and the #id with $item_target of each node in that axis.
For example: Attribute *$item_section=service* and the page id *target item_target=p1-1* should now recursively "walk" to the section branch "service" (depth 1), check if the target page #id is found on this level. In this case it is not found, so it makes the next recurive call (via apply-templates) to the next item node level (in this case it would be content-management-systems, there the target item page p1-1 is found, so the trail process is finished:
The result should like this:
home >> service >> content management systems >> p1-1
But unfortunately it is not working correct, at least not in every case. Also maybe it can be solved more easily. I try to implement it as an recursive template that walks from the top (level 0) to the target page (item node) as a leaf.
<!-- walk item path to generate a breadcrumb trail -->
<xsl:template name="breadcrumb">
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<xsl:value-of select="$req-lg"/>
<xsl:text>/home/index</xsl:text>
</xsl:attribute>
<xsl:value-of select="'Home'"/>
</a>
<xsl:apply-templates select="$content/site/index" mode="Item-Path">
<xsl:with-param name="item_section" select="'service'"/>
<xsl:with-param name="item_target" select="'search-engines-and-ir'"/>
<xsl:with-param name="depth" select="0"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="item" mode="Item-Path">
<xsl:param name="item_section" />
<xsl:param name="item_target" />
<xsl:param name="depth" />
<!--
depth=<xsl:value-of select="$depth"/>
count=<xsl:value-of select="count(./node())"/><br/>
-->
<xsl:variable name="cur-id" select="#id"/>
<xsl:variable name="cur-section" select="#section"/>
<xsl:choose>
<xsl:when test="#id=$item_target">
>>
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<!-- req-lg: global langauge variable -->
<xsl:value-of select="$req-lg"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="$item_section"/>
<xsl:text>/</xsl:text>
<xsl:if test="$depth = 2">
<xsl:value-of select="../#id"/>
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:value-of
select="$content/page[#id=$cur-id]/title"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:if test="ancestor-or-self::item/#section = $item_section and count(./node()) > 0">
>>:
<a>
<xsl:attribute name="href">
<xsl:text>/</xsl:text>
<!-- req-lg: global langauge variable -->
<xsl:value-of select="$req-lg"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="$item_section"/>
<xsl:text>/</xsl:text>
<xsl:if test="$depth = 2">
<xsl:value-of select="../#id"/>
<xsl:text>/</xsl:text>
</xsl:if>
<xsl:value-of select="#id"/>
</xsl:attribute>
<xsl:value-of
select="$content/page[#id=$cur-id and #section=$item_section]/title"/>
</a>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="item" mode="Item-Path">
<xsl:with-param name="item_section" select="$item_section"/>
<xsl:with-param name="item_target" select="$item_target"/>
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:apply-templates>
</xsl:template>
So as the hardcoded parameters in the template breadcrumb, target section = 'service' and target page = 'search-engines-and-ir', I expect an output like
home >> service >> search-engines-and-ir
But the output is
home >> service >> content-management-systems >> search-engines-and-ir
which is obviously not correct.
Can anybody give me a hint how to correct this issue? It would be even more elegant to avoid that depth checking, but up to now I cannot think of a other way, I am sure there is a more elegant solution.
I work with XSLT 1.0 (libxml via PHP5).
Hope my question is clear enough, if not, please ask :-) Thanks for the help in advance!
As simple as this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeById" match="item" use="#id"/>
<xsl:template match="/">
<xsl:text>home</xsl:text>
<xsl:call-template name="findPath">
<xsl:with-param name="pStart" select="'service'"/>
<xsl:with-param name="pEnd" select="'search-engines-and-ir'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="findPath">
<xsl:param name="pStart"/>
<xsl:param name="pEnd"/>
<xsl:for-each select=
"key('kNodeById', $pEnd)
[ancestor::item[#section=$pStart]]
[1]
/ancestor-or-self::item
[not(descendant::item[#section=$pStart])]
">
<xsl:value-of select=
"concat('>>', #id[not(../#section)], #section)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
the wanted, correct result is produced:
home>>service>>search-engines-and-ir
Do Note:
This solution prints the breadcrumb from any node -- anywhere in the hierarchy to any of its descendent nodes -- anywhere in the hierarchy. More precisely, for the first item (in document order) with id attribute equal to $pEnd, the breadcrumb is generated from its inner-most ancestor whose section attribute is equal to $pStart -- to that item element.
This solution should be much more efficient than any solution using //, because we are using a key to locate efficiently the "end" item element.
II. XSLT 2.0 solution:
Much shorter and easier -- an XPathe 2.0 single expression:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeById" match="item" use="#id"/>
<xsl:template match="/">
<xsl:value-of select=
"string-join(
(
'home',
key('kNodeById', $pEnd)
[ancestor::item[#section=$pStart]]
[1]
/ancestor-or-self::item
[not(descendant::item[#section=$pStart])]
/(#id[not(../#section)], #section)[1]
),
'>>'
)
"/>
</xsl:template>
</xsl:stylesheet>
You can just iterate over the ancestor-or-self:: axis . This is easy to do without recursion. For example...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html><body>
<xsl:call-template name="bread-crumbs">
<xsl:with-param name="items" select="*/item" />
<xsl:with-param name="section" select="'service'" />
<xsl:with-param name="leaf" select="'p1-2'" />
</xsl:call-template>
</body></html>
</xsl:template>
<xsl:template name="bread-crumbs">
<xsl:param name="items" />
<xsl:param name="section" />
<xsl:param name="leaf" />
<xsl:value-of select="concat($section,'>>')" />
<xsl:for-each select="$items/self::item[#section=$section]//item[#id=$leaf]/
ancestor-or-self::item[not(#section)]">
<xsl:value-of select="#id" />
<xsl:if test="position() != last()">
<xsl:value-of select="'>>'" />
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...on your sample input yields...
<html>
<body>service>>content-management-systems>>p1-2</body>
</html>
...which renders as...
service>>content-management-systems>>p1-2
This is the first time I have ever posted a question so apologese in advance if I jibber here.
I am trying to put together a CQWP with jQuery tabs slider functionality. The HTML I want to output should be in the form of 2 UL's. The first with li anchor tags with #associated-ul-id
The second ul's should have ids that associate with the list items in the first. Eg
<div id="tabs" class="news">
<div class="news-pagination">
« Prev
<ul id="carouseltext" class="horizontal-text order">
<li>System</li>
<li>School</li>
</ul>
» Next
<div class="clear"> </div>
</div>
<ul id="tabs-1" class="feed order">
<li>title 1</li>
<li>title 2</li>
</ul>
<ul id="tabs-2" class="feed order">
<li>title 3</li>
</ul>
</div>
The original XML starts off in the form
My XSL goes through the XML twice to fill the 2 ul's. The first time it just adds a new list item when the __begincolumn and __begingroup variables are true. I striped down the functionality here to just output the header. Here's a stripped down version of the XSL
<xsl:template match="/">
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="FirstRow" select="1" />
<xsl:param name="ColNumber" select="1" />
<xsl:for-each select="$Rows" >
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="BeginNewsItemsList1" select="string('<ul id="tabs-')" />
<xsl:variable name="BeginNewsItemsList2" select="string('"class="feed order">')" />
<xsl:variable name="BeginNewsItemsList" select="concat($BeginNewsItemsList1, $ColNumber, $BeginNewsItemsList2)" />
<xsl:if test="($CurPosition >= $FirstRow and $CurPosition <= $LastRow)">
<xsl:variable name="StartNewGroup" select="#__begingroup = 'True'" />
<xsl:variable name="StartNewColumn" select="#__begincolumn = 'True'" />
<xsl:when test="$StartNewGroup and $StartNewColumn">
<xsl:choose>
<xsl:when test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginNewsItemsList" />
</xsl:when>
<xsl:otherwise>
<!-- other instructions -->
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$StartNewGroup">
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
<xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginNewsItemsList)" />
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="OuterTemplate.Count">
<xsl:param name="ColNumber" />
<xsl:value-of select="$ColNumber + 1" />
</xsl:template>
For the second for-each loop I'm having trouble setting up a counter so that I can add the number to the end of the id for each new list id="tabs-1", id="tabs-2", etc.
In theory I think I should set a parameter outside my for-each loop and then in the loop call a template that gets the parameter value and increments it. That would mean it would increment only when the template is called.
I can't use position() for this as it doesn't correspond to the values I want. I've tried to follow a couple a few blogs about recursive programming with xsl, but I can't seem to find anything that works. I'm sure I'm just writing the XSL wrong, but I'm having a bit of a brain dump now.
If anybody could point me in the right direction that would be awesome. Thanks very much.
You can't change variable's values after declaration. You can use them in expressions and/or pass as parameters. Thus, you can't use outside variable as counter explicitly. One available trick is recursive cycle like:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<HTML>
<BODY>
<xsl:call-template name="for">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="n" select="5"/>
</xsl:call-template>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="for">
<xsl:param name="i"/>
<xsl:param name="n"/>
<xsl:value-of select="$i"/>
<xsl:if test="$i < $n">
<xsl:text>, </xsl:text>
<xsl:call-template name="for">
<xsl:with-param name="i" select="$i+1"/>
<xsl:with-param name="n" select="$n"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
result:
1, 2, 3, 4, 5
Does anyone know how to disable the current link in a breadcrumb trail.
I am working on a bspoke CMS and i have been asked to remove the current link in the breadcrumb trail.
All that i know in XSLT has failed and i have quite some time on, XSLT is no my strength and i need some helpful input.
Please help
here is the XSLT code:
[code]
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes" />
<!--
Variable to determine if the current open page is displayed as a link or plain text
select = 1 - displays plain text link
select = 0 - displays link (default value)
-->
<xsl:variable name="DisableCurrentPageLink" select="0" />
<xsl:template match="BreadCrumbTrail">
<xsl:apply-templates select="Page" />
</xsl:template>
<xsl:template match="Page">
<span class="BCTDelimiter">»</span>
<xsl:choose>
<xsl:when test="$DisableCurrentPageLink = 1">
<xsl:choose>
<xsl:when test="#IsOpenPage = 1">
<span class="breadcrumb-link">
<xsl:value-of select="#Title"/>
</span>
</xsl:when>
<xsl:otherwise>
<a href="{#URL}" class="breadcrumb-link" title="{#Title}">
<xsl:value-of select="#Title" />
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<a href="{#URL}" class="breadcrumb-link" title="{#Title}">
<xsl:value-of select="#Title" />
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
[/code]
It's hard without seeing the input form. That code will make an unlinked span for pages that have <page IsOpenPage="1"> as the markup, but does you CMS add that attribute for the relevant pages?
If the currently open page is always last in the trail you could change
<xsl:when test="#IsOpenPage = 1">
to
<xsl:when test="not(following-sibling::Page)">
I've got the following XSLT code which lists out the folders and their file items from a specified node.
This all works fine but I'd like to parameterise the page and optionally filter its output by a tag value.
Being an XLST numpty I'm stumped with the syntax for the conditional I should be putting in under the <xsl:when test="$tag"> clause - can someone please help ?
<xsl:variable name="tag" select="umbraco.library:Request('tag')" />
<xsl:template match="/">
<!-- Root folder in Media that holds the folders to output -->
<xsl:variable name="mediaRootFolderId" select="5948" />
<!-- Pass in true() to get XML for all nodes below -->
<xsl:variable name="mediaRootNode" select="umbraco.library:GetMedia($mediaRootFolderId, true())" />
<xsl:choose>
<xsl:when test="$tag">
</xsl:when>
<xsl:otherwise>
<!-- If we didn't get an error, output Folder elements that contain Image elements -->
<xsl:apply-templates select="$mediaRootNode[not(error)]/Folder[File]" >
<xsl:sort select="#nodeName"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Template for folders -->
<xsl:template match="Folder">
<div class="folder">
<h2>Folder: <xsl:value-of select="#nodeName" /></h2>
<div class="images">
<xsl:apply-templates select="File">
<xsl:sort select="#nodeName"/>
</xsl:apply-templates>
</div>
</div>
</xsl:template>
<!-- Template for files -->
<xsl:template match="File">
File: <a href="{umbracoFile}" alt="{#nodeName}" ><xsl:value-of select="#nodeName" /></a> <br/>
</xsl:template>
Instead of the long <xsl:choose> instruction, use:
<xsl:apply-templates select=
"$mediaRootNode[not($tag)][not(error)]
/Folder[File]" >
Explanation: For the XPath expression in the select attribute above to select a non-empty set of nodes it is necessary that boolean($tag) is true(). Thus the above single <xsl:apply-templates> instruction is equivalent to the long <xsl:choose> in the question.
you can test if $tag is set like this.
<xsl:param name="tag">
<xsl:message terminate="yes">
$tag has not been set
</xsl:message>
</xsl:param>
This isn't standard though, it'll work on most XSLT processors though.
If you wanted to be absolutely save, you could set the value to an illegal value (such as 1 div 0) and test for it in the body of the template:
<xsl:param name="tag" select="1 div 0" />
<xsl:if test="$tag = 1 div 0">
<xsl:message terminate="yes">
$tag has not been set, or has been set to Infinity, which is invalid.
</xsl:message>
</xsl:if>
Source: O'Reilly XSLT Cookbook