OK, I've inherited an Umbraco 4.5.2 site which has a macro which is supposed to iterate through child documents of type NewsDocument of the parent document type ListDocument. There are two examples on the site of this working fine. But when I create a new ListDocument document with NewsDocument child documents, I just get an empty unordered list element with no list items. Also when I make copies of the functioning ListDocuments and children (copied to the same parent document node as the two functioning ListDocuments), it doesn't work. It is very confusing as everything looks exactly the same.
I'm afraid my XSLT isn't good enough to understand what is going wrong. Here is the XSLT of the macro. I would appreciate any help finding out what is going wrong here. Thanks in advance.
<!-- This is the key definition using the set dateformat of the SomeDate documenttype field - all nodes with the same dateformat get same key id - we can't pass variables into this (limitation of xslt v1.0 to avoid circular references) - so need to generate all possible keys required for SortBy and ListBanner -
aslo UmbracoJPT:isCurrent(@id) needs to be here for some reason, but
the filter on hideInNavigation can't as it's a variable :-( --> <!-- start date is a custom field--> <xsl:key name="startDateY" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(startDate, 'Y')"/> <xsl:key name="startDateyyyy" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(startDate, 'yyyy')"/> <!-- create date is an inbuilt field so @--> <xsl:key name="createDateY" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@createDate, 'Y')"/> <xsl:key name="createDateyyyy" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@createDate, 'yyyy')"/>
<xsl:template match="/"> <xsl:if test="$debug"> <p class="Note"> sortOrder :<xsl:value-of select="$sortOrder"/> <br/> sortName :<xsl:value-of select="$sortName"/> <br/> listBanner :<xsl:value-of select="$listBanner"/> <br/> hiddenInNavigation :<xsl:value-of select="$hiddenInNavigation"/> </p> </xsl:if> <!--Make sure we have some items--> <xsl:if test="count($parent/* [@isDoc]) > 0"> <xsl:if test="string($node/@id) = false() and ($hideRSS = '0' or $hideRSS = false())"> <p><a title="Subscribe to RSS feed" class="RssLink" href="{concat(umbraco.library:NiceUrl($parent/@id),'/rss')}">Subscribe to RSS feed</a></p> </xsl:if> <xsl:choose> <xsl:when test="$listBanner = '0'"> <ul class="List {$class}"> <xsl:apply-templates select="$parent/*
[@isDoc and UmbracoJPT:isCurrent(@id) and (hideInNavigation =
$hiddenInNavigation or ($hiddenInNavigation = '-1' or
$hiddenInNavigation = false()))]"> <xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/> </xsl:apply-templates> </ul> </xsl:when> <xsl:otherwise> <ul class="List {$class}"> <!-- Iterate over all nodes with an id similar to the first in every group --> <xsl:for-each select="$parent/*[generate-id()
= generate-id(key(concat($sortName,$listBanner),
umbraco.library:FormatDateTime((@*|./*)[name()=$sortName],
$listBanner))[1]) and (hideInNavigation = $hiddenInNavigation or
($hiddenInNavigation = '-1' or $hiddenInNavigation = false()))]"> <xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/> <li class="DateBanner"> <strong> <xsl:value-of select="umbraco.library:FormatDateTime((@*|./*)[name()=$sortName], $listBanner)"/> </strong> <ul>
<!-- Iterate over all nodes in a group, i.e. with the same key --> <xsl:apply-templates select="key(concat($sortName,$listBanner),umbraco.library:FormatDateTime((@*|./*)[name()=$sortName], $listBanner))"> <xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/> </xsl:apply-templates>
<xsl:template match="*[@isDoc]"> <xsl:if test="position() <= $numberOfItems or ($numberOfItems = 0 or string(number($numberOfItems)) = 'NaN')"> <li> <xsl:variable name="liClass"> <!-- add a Newish class if release in the last x days --> <xsl:if test="contains($sortBy, 'Date')"> <xsl:variable name="datediff" select="umbraco.library:DateDiff(umbraco.library:ShortDate(umbraco.library:CurrentDate()),
umbraco.library:ShortDate((@*|./*)[name()=$sortName]), 'm')" /> <xsl:if test="$datediff < (1440 * $lastXDays)">Newish</xsl:if> </xsl:if> <!-- add a class for columns if required --> <xsl:if test="number($columns) > 1"> Column<xsl:value-of select="(position()-1) mod number($columns)"/> </xsl:if> <!-- add a class for first item if required note first in a list (could be a sublist eg listbanner) --> <xsl:if test="position() = 1"> First </xsl:if> <!-- add a class for last item if required note last in a list (could be a sublist eg listbanner) --> <xsl:if test="position() = last() or position() = $numberOfItems"> Last </xsl:if> </xsl:variable>
<xsl:if test="./memberRole != false() and
./memberRole != '' and ($hideRole = false() or $hideRole = '0')"> <em><xsl:value-of select="./memberRole"/></em> </xsl:if> <xsl:if test="./memberRole = false() or ./memberRole = ''"> <xsl:if test="./writtenBy != false() and ./writtenBy != ''"> <em><xsl:value-of select="./writtenBy"/></em> </xsl:if> </xsl:if>
<xsl:if test="$abstractLength > 0"> <xsl:choose> <xsl:when test="./abstract != false() and ./abstract != ''"> <xsl:variable name="XmlAbstract" select="UmbracoJPT:ParseStringAsXml(./abstract)"/> <xsl:variable name="strippedHTML" select="umbraco.library:StripHtml($XmlAbstract//p[1])"/> <xsl:value-of select="substring($strippedHTML, 1, $abstractLength)" /> <!-- add an elipsis if there is more text than we are showing on the search results page --> <xsl:if test="string-length($strippedHTML) > $abstractLength">...</xsl:if> </xsl:when> <xsl:otherwise> <xsl:variable name="strippedHTML" select="umbraco.library:StripHtml(($XmlContent//p)[1])"/> <xsl:value-of select="substring($strippedHTML, 1, $abstractLength)" /> <!-- add an elipsis if there is more text than we are showing on the search results page --> <xsl:if test="string-length($strippedHTML) > $abstractLength">...</xsl:if> </xsl:otherwise> </xsl:choose> </xsl:if> <xsl:if test="contains($sortBy, 'Date') and $showDate = '1'"> <xsl:choose> <xsl:when test="$dateFormat = 'Graphical'"/> <xsl:when test="$dateFormat = 'graphical'"/> <xsl:otherwise> <xsl:value-of select="UmbracoJPT:FormatDate((@*|./*)[name()=$sortName],$dateFormat)"/> </xsl:otherwise> </xsl:choose>
XSLT list macro not working
OK, I've inherited an Umbraco 4.5.2 site which has a macro which is supposed to iterate through child documents of type NewsDocument of the parent document type ListDocument. There are two examples on the site of this working fine. But when I create a new ListDocument document with NewsDocument child documents, I just get an empty unordered list element with no list items. Also when I make copies of the functioning ListDocuments and children (copied to the same parent document node as the two functioning ListDocuments), it doesn't work. It is very confusing as everything looks exactly the same.
I'm afraid my XSLT isn't good enough to understand what is going wrong. Here is the XSLT of the macro. I would appreciate any help finding out what is going wrong here. Thanks in advance.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:UmbracoJPT="urn:JPT.Util"
xmlns:UmbracoJPT.Files="urn:JPT.Files"
xmlns:umbraco.library="urn:umbraco.library"
xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon"
xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes"
xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath"
xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions"
xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings"
xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets UmbracoJPT UmbracoJPT.Files">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="currentPage"/>
<xsl:variable name="debug" select="false()"/>
<xsl:variable name="hideRSS" select="/macro/HideRSS" />
<xsl:variable name="numberOfItems" select="/macro/NumberOfItems"/>
<xsl:variable name="abstractLength" select="/macro/AbstractLength"/>
<xsl:variable name="showAbstract" select="/macro/ShowAbstract"/>
<xsl:variable name="showThumbnail" select="/macro/ShowThumbnail"/>
<xsl:variable name="thumbnailSize" select="/macro/ThumbnailSize"/>
<xsl:variable name="parentId" select="/macro/ParentId"/>
<!-- The attribute in the node to sort by (createDate, updateDate, nodeName etc.) OR a 'friendly title' from page property -->
<xsl:variable name="sortBy" select="/macro/SortBy"/>
<xsl:variable name="sortByIsAttribute">
<xsl:choose>
<xsl:when test="starts-with($sortBy, '@')">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="sortName">
<xsl:choose>
<xsl:when test="starts-with($sortBy, '@')">
<xsl:value-of select="substring-after($sortBy,'@')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$sortBy"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Sort direction - either 'ascending' or 'descending' -->
<xsl:variable name="ascending" select="/macro/Ascending"/>
<xsl:variable name="sortOrder">
<xsl:choose>
<xsl:when test="$ascending = 1">ascending</xsl:when>
<xsl:otherwise>descending</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="showDate" select="/macro/ShowDate"/>
<xsl:variable name="dateFormat" select="/macro/DateFormat"/>
<xsl:variable name="listMacroBanner" select="/macro/ListBanner"/>
<xsl:variable name="listBanner">
<xsl:choose>
<xsl:when test="$listMacroBanner = '' or $listMacroBanner = false()">
<xsl:value-of select="string(0)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="string($listMacroBanner)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="class" select="/macro/Class"/>
<xsl:variable name="columns" select="/macro/Columns"/>
<xsl:variable name="hiddenInNavigation" select="/macro/HiddenInNavigation"/>
<xsl:variable name="lastXDays" select="/macro/LastXDays" />
<xsl:variable name="node" select="umbraco.library:GetXmlNodeById($parentId)" />
<xsl:variable name="parentXML">
<xsl:choose>
<xsl:when test="string($node/@id) = false()">
<xsl:copy-of select="$currentPage"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="umbraco.library:GetXmlNodeById($parentId)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="parent" select="msxml:node-set($parentXML)/*"/>
<xsl:variable name="ulOpen">
<xsl:text><ul class="List </xsl:text>
<xsl:value-of select="$class"/>
<xsl:text>" ></xsl:text>
</xsl:variable>
<xsl:variable name="ulClose">
<xsl:text></ul></xsl:text>
</xsl:variable>
<xsl:variable name="ulOpenNoClass">
<xsl:text><ul></xsl:text>
</xsl:variable>
<xsl:variable name="hideRole" select="/macro/HideRole" />
<!-- This is the key definition using the set dateformat of the SomeDate documenttype field
- all nodes with the same dateformat get same key id
- we can't pass variables into this (limitation of xslt v1.0 to avoid circular references)
- so need to generate all possible keys required for SortBy and ListBanner
- aslo UmbracoJPT:isCurrent(@id) needs to be here for some reason, but the filter on hideInNavigation can't as it's a variable :-(
-->
<!-- start date is a custom field-->
<xsl:key name="startDateY" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(startDate, 'Y')"/>
<xsl:key name="startDateyyyy" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(startDate, 'yyyy')"/>
<!-- create date is an inbuilt field so @-->
<xsl:key name="createDateY" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@createDate, 'Y')"/>
<xsl:key name="createDateyyyy" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@createDate, 'yyyy')"/>
<xsl:key name="updateDateY" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@updateDate, 'Y')"/>
<xsl:key name="updateDateyyyy" match="*[@isDoc and UmbracoJPT:isCurrent(@id)]" use="umbraco.library:FormatDateTime(@updateDate, 'yyyy')"/>
<!--
<xsl:key name="nodeNameY" match="*" use="umbraco.library:FormatDateTime(nodeName, 'Y')"/>
<xsl:key name="nodeNameyyyy" match="*" use="umbraco.library:FormatDateTime(nodeName, 'yyyy')"/> -->
<xsl:template match="/">
<xsl:if test="$debug">
<p class="Note">
sortOrder :<xsl:value-of select="$sortOrder"/>
<br/>
sortName :<xsl:value-of select="$sortName"/>
<br/>
listBanner :<xsl:value-of select="$listBanner"/>
<br/>
hiddenInNavigation :<xsl:value-of select="$hiddenInNavigation"/>
</p>
</xsl:if>
<!--Make sure we have some items-->
<xsl:if test="count($parent/* [@isDoc]) > 0">
<xsl:if test="string($node/@id) = false() and ($hideRSS = '0' or $hideRSS = false())">
<p><a title="Subscribe to RSS feed" class="RssLink" href="{concat(umbraco.library:NiceUrl($parent/@id),'/rss')}">Subscribe to RSS feed</a></p>
</xsl:if>
<xsl:choose>
<xsl:when test="$listBanner = '0'">
<ul class="List {$class}">
<xsl:apply-templates select="$parent/* [@isDoc and UmbracoJPT:isCurrent(@id) and (hideInNavigation = $hiddenInNavigation or ($hiddenInNavigation = '-1' or $hiddenInNavigation = false()))]">
<xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/>
</xsl:apply-templates>
</ul>
</xsl:when>
<xsl:otherwise>
<ul class="List {$class}">
<!-- Iterate over all nodes with an id similar to the first in every group -->
<xsl:for-each select="$parent/*[generate-id() = generate-id(key(concat($sortName,$listBanner), umbraco.library:FormatDateTime((@*|./*)[name()=$sortName], $listBanner))[1]) and (hideInNavigation = $hiddenInNavigation or ($hiddenInNavigation = '-1' or $hiddenInNavigation = false()))]">
<xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/>
<li class="DateBanner">
<strong>
<xsl:value-of select="umbraco.library:FormatDateTime((@*|./*)[name()=$sortName], $listBanner)"/>
</strong>
<ul>
<!-- Iterate over all nodes in a group, i.e. with the same key -->
<xsl:apply-templates select="key(concat($sortName,$listBanner),umbraco.library:FormatDateTime((@*|./*)[name()=$sortName], $listBanner))">
<xsl:sort select="(@*|./*)[name()=$sortName]" order="{$sortOrder}"/>
</xsl:apply-templates>
</ul>
</li>
</xsl:for-each>
</ul>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template match="*[@isDoc]">
<xsl:if test="position() <= $numberOfItems or ($numberOfItems = 0 or string(number($numberOfItems)) = 'NaN')">
<li>
<xsl:variable name="liClass">
<!-- add a Newish class if release in the last x days -->
<xsl:if test="contains($sortBy, 'Date')">
<xsl:variable name="datediff" select="umbraco.library:DateDiff(umbraco.library:ShortDate(umbraco.library:CurrentDate()), umbraco.library:ShortDate((@*|./*)[name()=$sortName]), 'm')" />
<xsl:if test="$datediff < (1440 * $lastXDays)">Newish</xsl:if>
</xsl:if>
<!-- add a class for columns if required -->
<xsl:if test="number($columns) > 1">
Column<xsl:value-of select="(position()-1) mod number($columns)"/>
</xsl:if>
<!-- add a class for first item if required note first in a list (could be a sublist eg listbanner) -->
<xsl:if test="position() = 1">
First
</xsl:if>
<!-- add a class for last item if required note last in a list (could be a sublist eg listbanner) -->
<xsl:if test="position() = last() or position() = $numberOfItems">
Last
</xsl:if>
</xsl:variable>
<xsl:if test="normalize-space($liClass) != ''">
<xsl:attribute name="class">
<xsl:value-of select="normalize-space($liClass)"/>
</xsl:attribute>
</xsl:if>
<a href="{umbraco.library:NiceUrl(@id)}" title="{./altTitle}">
<xsl:variable name="XmlContent" select="UmbracoJPT:ParseStringAsXml(./content)"/>
<xsl:variable name="FirstImg" select="($XmlContent//img)[1]"/>
<xsl:if test="contains($sortBy, 'Date') and $showDate = '1'">
<xsl:choose>
<xsl:when test="$dateFormat = 'Graphical'">
<span class="Date1">
<span class="Day">
<xsl:value-of select="Exslt.ExsltDatesAndTimes:dayinmonth((@*|./*)[name()=$sortName])" />
</span>
<span class="Month">
<xsl:value-of select="Exslt.ExsltDatesAndTimes:monthabbreviation((@*|./*)[name()=$sortName])" />
</span>
<span class="Year">
<xsl:value-of select="Exslt.ExsltDatesAndTimes:year((@*|./*)[name()=$sortName])" />
</span>
</span>
</xsl:when>
<xsl:when test="$dateFormat = 'graphical'">
<span class="Date2">
<span class="Month">
<xsl:value-of select="Exslt.ExsltDatesAndTimes:monthabbreviation((@*|./*)[name()=$sortName])" />
</span>
<span class="Day">
<xsl:value-of select="Exslt.ExsltDatesAndTimes:dayinmonth((@*|./*)[name()=$sortName])" />
</span>
</span>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:if>
<xsl:if test="$showThumbnail = 1 and $thumbnailSize > 0">
<xsl:choose>
<xsl:when test="./alternativeThumbnail != false() and ./alternativeThumbnail != ''">
<xsl:variable name="media" select="umbraco.library:GetMedia(./alternativeThumbnail, 0)" />
<xsl:if test="UmbracoJPT.Files:ShowThumbnail($media/umbracoFile,$thumbnailSize) != ''">
<img src="{UmbracoJPT.Files:ShowThumbnail($media/umbracoFile,$thumbnailSize)}" alt="{$FirstImg/@alt}" title="{$FirstImg/@alt}"/></xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="UmbracoJPT.Files:ShowThumbnail($FirstImg/@src,$thumbnailSize) != ''">
<img src="{UmbracoJPT.Files:ShowThumbnail($FirstImg/@src,$thumbnailSize)}" alt="{$FirstImg/@alt}" title="{$FirstImg/@alt}"/></xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<strong>
<xsl:value-of select="@nodeName"/>
</strong>
<xsl:if test="./memberRole != false() and ./memberRole != '' and ($hideRole = false() or $hideRole = '0')">
<em><xsl:value-of select="./memberRole"/></em>
</xsl:if>
<xsl:if test="./memberRole = false() or ./memberRole = ''">
<xsl:if test="./writtenBy != false() and ./writtenBy != ''">
<em><xsl:value-of select="./writtenBy"/></em>
</xsl:if>
</xsl:if>
<xsl:if test="$abstractLength > 0">
<xsl:choose>
<xsl:when test="./abstract != false() and ./abstract != ''">
<xsl:variable name="XmlAbstract" select="UmbracoJPT:ParseStringAsXml(./abstract)"/>
<xsl:variable name="strippedHTML" select="umbraco.library:StripHtml($XmlAbstract//p[1])"/>
<xsl:value-of select="substring($strippedHTML, 1, $abstractLength)" />
<!-- add an elipsis if there is more text than we are showing on the search results page -->
<xsl:if test="string-length($strippedHTML) > $abstractLength">...</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="strippedHTML" select="umbraco.library:StripHtml(($XmlContent//p)[1])"/>
<xsl:value-of select="substring($strippedHTML, 1, $abstractLength)" />
<!-- add an elipsis if there is more text than we are showing on the search results page -->
<xsl:if test="string-length($strippedHTML) > $abstractLength">...</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="contains($sortBy, 'Date') and $showDate = '1'">
<xsl:choose>
<xsl:when test="$dateFormat = 'Graphical'"/>
<xsl:when test="$dateFormat = 'graphical'"/>
<xsl:otherwise>
<xsl:value-of select="UmbracoJPT:FormatDate((@*|./*)[name()=$sortName],$dateFormat)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</a>
</li>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
is working on a reply...