Umbraco XSLT select newsitem sub nodes regardless of currentpage - xslt

I need to say; I'm pretty green in xslt so, most likely, that's the main problem; nonetheless been on it for hours and can't get it.
I want to fill a column on my main template with the 5 most recent newsitems. These newsitems should be shown regardless of the currentpage.
I've tried this:
<xsl:template match="/">
<xsl:for-each select="umbraco.library:GetXmlNodeById(1075)/child::node">
<p>
<strong>
<xsl:value-of select="header"/>
</strong>
</p>
</xsl:for-each>
</xsl:template>
Where, at the moment, 1075 is my News template. Ive tried it with just: GetXmlNodeById(1076)/node (where 1076) is my NewsItem template. I've tried it with the node-Id's from the content-tree, but no luck..
Anyone able to help me out here? Am stuck and I've searched high and low on Google, the forums and documentation, but I'm most likely missing something vital here. TIA!
P.S. Using Umbraco 4.5 BTW

This should output current and child nodes.
<xsl:copy-of select="umbraco.library:GetXmlNodeById(1075)"/>
In Umbraco 4.5 the schema has changed, from /node[#nodeTypeAlias='News'] to /News [#isDoc]
http://blog.leekelleher.com/2010/04/02/working-with-xslt-using-new-xml-schema-in-umbraco-4-1/
So your xslt should look like
<xsl:template match="/">
<ul>
<xsl:for-each select="umbraco.library:GetXmlNodeById(1075)/News [#isDoc]">
<li><xsl:value-of select="#nodeName"/></li>
</xsl:for-each>
</ul>
</xsl:template>

Related

(Umbraco) How can I list related pages by tags?

In the last node of my site is where the articles are shown, and everyone has its own tags that of course can be the same between some of them, so I wrote a Macro for tags that is working (it lists the tags of the article the user is viewing), I've used the Tag datatype for my 'Article' doctype, and that Macro works correctly; but I got problems with the Macro I wrote to list those articles that have the same tags, I called it RelatedContent.xslt. Here is the code for AllTags.xslt that I found in Umbraco TV Tutorials that works:
<xsl:template match="/">
<div class="tags">
<xsl:variable name="Factor" select="6 div Exslt.ExsltMath:max(tags:getAllTagsInGroup('default')/tags/tag/#nodesTagged)"/>
<xsl:for-each select="tags:getAllTagsInGroup('default')/tags/tag">
<a class="tag{round($Factor * #nodesTagged)}x" href="?tag={.}">
<xsl:value-of select="."/>
</a><br/>
</xsl:for-each>
</div>
</xsl:template>
And the code for RelatedContent.xslt is this:
<xsl:template match="/">
<ul>
<xsl:for-each select="$currentPage/node [string(data [#alias='umbracoNaviHide']) != '1'] and (umbraco.library:Request('tag') = '' or contains(data [#alias = 'tags'], umbraco.library:Request('tag')))">
<li>
<a href="{umbraco.library:NiceUrl(#id)}">
<xsl:value-of select="#nodeName"/>
<xsl:value-of select="newsTitle"/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
I have not found anything to help me understand this, so I cannot realize how to do it. I will appreciate some help from you. Thanks for your advices.
(Umbraco 6.1.3)
The code for the related content is using the old XML Schema.
Replace this bit:
<xsl:for-each select="$currentPage/node [string(data [#alias='umbracoNaviHide']) != '1']
and (umbraco.library:Request('tag') = '' or contains(data [#alias = 'tags'],
umbraco.library:Request('tag')))">
</xsl:for-each>
With
<xsl:variable name="tag" select="umbraco.library:Request('tag')"/>
<xsl:for-each select="$currentPage/*[#isDoc][umbracoNaviHide != 1][contains($tag,./tag)]">
</xsl:for-each>
The /node element does not exist in the 4.6+ schema, and the element name is replaced with the name of the documentTypeAlias.
So if you have a document type article with a property articleTitle it would be like this:
$currentPage/article/
$currentPage/article/articleTitle
Instead of the old schema (this is incorrect for anything above 4.5)
$currentPage/node[#nodeTypeAlias = 'article']
$currentPage/node[./data[#alias] = 'articleTitle']
You can see the difference between the 2 schemas at the Umbraco wiki:
http://our.umbraco.org/wiki/reference/xslt/45-xml-schema

How to make XSLT xsl:if work

I am trying to make this (xml 1.0) code work . I am new to this and already exhausted myself in
trying different ways. Does someone know my mistake?
<xsl:for-each select="News/Sport">
<xsl:if test="local-name()='Basketball'">
<p>
<xsl:text>Basketball Sport</xsl:text>
</p>
<xsl:value-of select="News/Sport/Basketball/Phrases/Phrase"/>
</xsl:if>
</xsl:for-each>
When I transform it into an HTML file the content doesn't show up. When I remove the xsl:for each and the xsl:if statements the content is successfully presented. I only wish that the content is first checked (if it is available in the XML file) and if yes, that it is taken from the XML content.
Thank you in advance for your help!
EDIT:
This is my XML code
<News>
<Sport>
<Basketball>
<Phrases>
<Phrase>Zach Randolph recovered the opening tipoff in Game 1 of the Western Conference Finals, and he didn’t touch the ball again until the possession following the Grizzlies’ first timeout.
</Phrase>
<Phrases>
</Basketball>
</Sport>
</News>
EDIT2:
Could you tell me why I cannot apply a template inside this below function? Only the text works now:(
<xsl:for-each select="News/Sport[Basketball]">
<xsl:apply-templates select="News/Sport/*" />
</xsl:for-each>
<xsl:template match="Basketball">
<p>
<xsl:text>Basketball Sport</xsl:text>
</p>
<xsl:apply-templates select="Phrases/Phrase"/>
</xsl:template>
<xsl:for-each select="News/Sport">
<xsl:if test="local-name()='Basketball'">
In this if test, the context node is a Sport element, so local-name() will always be Sport and will never equal Basketball.
I only wish that the content is first checked (if it is available in the XML file) and if yes, that it is taken from the XML content.
The usual way to handle this sort of thing in XSLT is to define templates matching the various nodes that might be present and then applying templates to all the nodes that are actually found. If there are no nodes of a particular type then the corresponding template will not fire
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:template match="/">
<html>
<body>
<!-- apply templates that match all elements inside Sport, which may
be Basketball, Football, etc. -->
<xsl:apply-templates select="News/Sport/*" />
</body>
</html>
</xsl:template>
<!-- when we find a Basketball element ... -->
<xsl:template match="Basketball">
<p>
<xsl:text>Basketball Sport</xsl:text>
</p>
<xsl:apply-templates select="Phrases/Phrase"/>
</xsl:template>
<!-- when we find a Football element ... -->
<xsl:template match="Football">
<p>
<xsl:text>Football Sport</xsl:text>
</p>
<!-- whatever you need to do for Football elements -->
</xsl:template>
<xsl:template match="Phrase">
<p><xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
That way you don't need any explicit for-each or if, the template matching logic handles it all for you.
You are missing the idea of a context node. Within a xsl:for-each, everything you refer to is about or relative to the selected nodes. So, for instance, within <xsl:for-each select="News/Sport">, the context node is the Sport elements, and a test like <xsl:if test="local-name()='Basketball'"> is always going to be false because the local name is always Sport.
It looks like you want just <xsl:if test="Basketball"> which tests whether there are any Basketball child nodes of the current Sport node.
The same thing applies to <xsl:value-of select="News/Sport/Basketball/Phrases/Phrase"/>. Because everything is relative to the Sport node, XSLT is looking for News/Sport/Basketball/Phrases/Phrase within the Sport element, which never exists.
In addition, you can just put text in literally: there is no need for an xsl:text element here, so your code should look like
<xsl:for-each select="News/Sport">
<xsl:if test="Basketball">
<p>Basketball Sport</p>
<xsl:value-of select="Basketball/Phrases/Phrase"/>
</xsl:if>
</xsl:for-each>
You can refine this further by adding a predicate to the for-each selection, so that it matches only Sport elements with a Basketball child. Like this
<xsl:for-each select="News/Sport[Basketball]">
<p>Basketball Sport</p>
<xsl:value-of select="Basketball/Phrases/Phrase"/>
</xsl:for-each>

Using a link in XSL Files

I am completely new to XML so hopefully my explanations will make sense..
I am using an XSL file with 2 sections of HTML text, reading from 2 templates set up within the file.
The first text and associated template is a table, and I have set up a link within that. I want the link to then point to a picture that is part of the 2nd HTML text/template.
The link in the table is setup in that it appears as a link, underlined, etc. However it doesnt go anywhere when clicked.
The second section works fine on it's own, eg, pictures and text appears.
But what I cant figure out is how to actually get the link to work. I've tried numerous things but nothing has worked so far. And I-m not sure whether I am very close and just perhaps need to alter a line of code. Or whether I need to be doing something very different. Also, there are no error messages, and everything displays well, it's just the link itself that doesnt work.
<xsl:template match="portion">
<tr>
<td valign="top"><xsl:value-of select="food-description"/></td>
<td valign="top"><xsl:value-of select="food-number"/></td>
<!--the following is the link text-->
<td valign="top"><a><xsl:attribute name="href">#<xsl:value-of select="portion- photo/#file"/></xsl:attribute>
<xsl:value-of select="portion-photo/#file"/></a><br/>
</td>
</tr>
</xsl:template>
<xsl:template match="portion-photo">
<!--I know that this is the code that is not correct, however, believe it should be something similar-->
<a><xsl:attribute name="portion-photo"><xsl:value-of select="./#file"/></xsl:attribute></a>
<p><xsl:value-of select="../food-description"/>
<xsl:value-of select="./#file"/></p>
<img>
<xsl:attribute name="src"><xsl:value-of select="./#file"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="ceiling(./#w div v2)"/></xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="ceiling(./#h div 2)"/></xsl:attribute>
</img>
</xsl:template>
Something like the following should work. Just add the missing name attribute to the anchor element:
<xsl:template match="portion">
...
<a href="#{portion-photo/#file}">
<xsl:value-of select="portion-photo/#file"/>
</a>
...
</xsl:template>
<xsl:template match="portion-photo">
<a name="{#file}">
<xsl:value-of select="#file"/>
</a>
</xsl:template>
However, you have to ensure that #file evaluates to a valid anchor name. If the values of all file attributes are unique, you could also create save IDs with generate-id():
<xsl:template match="portion">
...
<a href="#{generate-id(portion-photo)}">
<xsl:value-of select="portion-photo/#file"/>
</a>
...
</xsl:template>
<xsl:template match="portion-photo">
<a name="{generate-id()}">
<xsl:value-of select="#file"/>
</a>
</xsl:template>

How to dynamically assign name and href for anchor tag in xsl

I have a requirement where the xml might have one or more services (name might be different), and I am having a content which should have all of these available services from the xml something like below
<li>CMS</li>
<li>DIS</li>
but above I have hardcoded the a tag content and href since I know these are the values, but in real time I would not be knowing these names, so how to set href and anchor tag contents based on xml values?
So far I got the below for-each statement, which gets me all the service names from the xml
<xsl:variable name="number">
<xsl:number/>
</xsl:variable>
<xsl:for-each select="csmclient/product/domainmetadata/domainmetadata_service">
<li><xsl:value-of select="#name"/><xsl:value-of select="position()"/></li>
</xsl:for-each>
.
.
.
<!--far below end-->
<xsl:for-each select="domainmetadata/domainmetadata_service">
<h3>Service Name: <span style="color:#328aa4"><a name="_ser{$number}" href="#_top"><xsl:value-of select="#name"/></a></span></h3>
.
.
.
</xsl:for-each>
but it does not seem to work, it gives me all my services but the link does not work. Any other ideas?
Note: I took help from this question link which had a similar requirement.
There is a xslt function generate-id() which gives and unique textual identifier for any node in the xml.
http://www.w3.org/TR/xslt#function-generate-id
Use something like below, should work
<xsl:for-each select="csmclient/product/domainmetadata/domainmetadata_service">
<li><xsl:value-of select="#name"/></li>
</xsl:for-each>
<xsl:for-each select="domainmetadata/domainmetadata_service">
<h3>Service Name: <span style="color:#328aa4"><a name="{generate-id()}" href="#_top"><xsl:value-of select="#name"/></a></span></h3>
</xsl:for-each>
<li><xsl:value-of select="#name"/><xsl:value-of select="position()"/></li>
but it does not seem to work ...
What you are trying to write is this (not discussing at all if this uniquely identifies the node):
<li>
<a href="#_ser{$number}{#name}{position()}"/>
</li>

Hyperlinks within XSLT Templates

I am trying to create hyperlinks using XML information and XSLT templates. Here is the XML source.
<smartText>
Among individual stocks, the top percentage gainers in the S. and P. 500 are
<smartTextLink smartTextRic="http://investing.domain.com/research/stocks/snapshot
/snapshot.asp?ric=HBAN.O">Huntington Bancshares Inc</smartTextLink>
and
<smartTextLink smartTextRic="http://investing.domain.com/research/stocks/snapshot
/snapshot.asp?ric=EK">Eastman Kodak Co</smartTextLink>
.
</smartText>
I want the output to look like this, with the company names being hyperlinks based on the "smartTextLink" tags in the Xml.
Among individual stocks, the top percentage gainers in the S.&P. 500 are Eastman Kodak Co and Huntington Bancshares Inc.
Here are the templates that I am using right now. I can get the text to display, but not the hyperlinks.
<xsl:template match="smartText">
<p class="smartText">
<xsl:apply-templates select="child::node()" />
</p>
</xsl:template>
<xsl:template match="smartTextLink">
<a>
<xsl:apply-templates select="child::node()" />
<xsl:attribute name="href">
<xsl:value-of select="#smartTextRic"/>
</xsl:attribute>
</a>
</xsl:template>
I have tried multiple variations to try to get the hyperlinks to work correctly. I am thinking that the template match="smartTextLink" is not being instantiated for some reason. Does anyone have any ideas on how I can make this work?
EDIT: After reviewing some of the answers, it is still not working in my overall application.
I am calling the smartText template from within my main template
using the following statement...
<xsl:value-of select="marketSummaryModuleData/smartText"/>
Could this also be a part of the problem?
Thank you
Shane
Either move the xsl:attribute before any children, or use an attribute value template.
<xsl:template match="smartTextLink">
<a href="{#smartTextRic}">
<xsl:apply-templates/>
</a>
</xsl:template>
From the creating attributes section of the XSLT 1 spec:
The following are all errors:
Adding an attribute to an element after children have been added to it; implementations may either signal the error or ignore the attribute.
Try this - worked for me:
<xsl:template match="smartText">
<p class="smartText">
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="smartTextLink">
<a>
<xsl:attribute name="href">
<xsl:value-of select="#smartTextRic"/>
</xsl:attribute>
<xsl:value-of select="text()"/>
</a>
</xsl:template>
Trick is - <xsl:attribute> first, before you do any other processing.
Marc