hey guys, im creating a online jquery slideshow using umbraco and have come across some things i am unsure of. I have a layout like below, I have a master template which has a xslt which shows all the slides by $currentPage/descendant-or-self::* However i would like one of my pages to display the 3 child elements which contain information about product etc. My slidehow has a structure like below
What is the best way to call these pages? Can i do this via apply template or is it worth including external xslt files? Below is what i have as a starting point.
<xsl:param name="currentPage"/> <xsl:template match="/"> <ul> <xsl:apply-templates select="$currentPage/descendant-or-self::* [@isDoc and string(umbracoNaviHide) != '1']" /> </ul> </xsl:template> <xsl:template match="*[@isDoc]"> <xsl:if test="@nodeName = 'Slide 1' "> bbhjkhjkhjk <xsl:apply-templates select="product" /> </xsl:if> </xsl:template> <xsl:template match="product"> <li> <article class="spot1"> <div class="product_images"> <img src="/new_images/magazine/magazine_top5_product1.jpg" alt="main product shot 1" /> <div class="description"> <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> </div> <h2>hahahah thisd is a test</h2> </div> </article> </li> </xsl:template> </xsl:stylesheet>
You don't even need to test if you're on 'Slide 1' - what if you decide to put products under another one next week?
Using apply-templates it all just works - when you say <xsl:apply-templates select="product" /> , the processor will collect all <product> elements under the current node, if there ain't any, nothing will happen - tada! :-)
Could be a couple of things, most likely due to CasE-sENsitivitY - on the face of it, I'd say your product ought to be Product if it's a seperate DocumentType (lowercase elements are almost always properties.) - so:
<xsl:template match="/">
<!-- In here, / refers to the rootnode of the <macro> XML document... -->
<!-- So we need to get into the Umbraco XML using $currentPage as a starter. -->
<!-- Here, we take all descendants of the current page -->
<xsl:apply-templates select="$currentPage//*[@isDoc][not(umbracoNaviHide = 1)]" />
</xsl:template>
<!-- Match any Umbraco DocumentType -->
<xsl:template match="*[@isDoc]">
<!-- Do something with it -->
<!-- Process any <Product> childnodes -->
<xsl:apply-templates select="Product" />
</xsl:template>
<xsl:template match="Product">
<!-- Hey - we found a Product node -->
<p>
I'm a Product
</p>
</xsl:template>
Thanks for the reply chriztan, i think i was half asleep when i replied last night. I still cant get the template match to work, My site structure is more like below, i forgot to include the table of contents
first slide (which includes first cover) ---table of contents -----------slide 1--- ---------------------product 1 ---------------------product 2 ---------------------product 3 -----------slide 2--- -----------slide 3--- -----------slide 4---
I changed my doc type and it hasnt made a difference
<xsl:param name="currentPage"/> <xsl:template match="/"> <!-- In here, / refers to the rootnode of the <macro> XML document... --> <!-- So we need to get into the Umbraco XML using $currentPage as a starter. --> <!-- Here, we take all descendants of the current page --> <xsl:apply-templates select="$currentPage/descendant-or-self::*[@isDoc][not(umbracoNaviHide = 1)]" /> </xsl:template> <!-- Match any Umbraco DocumentType --> <xsl:template match="*[@isDoc]"> <!-- Do something with it --> <!-- Process any <Product> childnodes --> <xsl:apply-templates select="Product" /> </xsl:template> <xsl:template match="Product"> <!-- Hey - we found a Product node --> <p> I'm a Product </p> </xsl:template>
Okay, the template matching *[@isDoc] seems to be preventing the Product template from matching. I'm still not 100% sure about where in your structure you are using this, so maybe this is not entirely relevant, but if I have the structure:
...and with $currentPage as EventsPage print out name() from the *[@isDoc] template, I get:
EventsPage EventsItem EventsItem EventsItem
...but the EventsItem specific template (i.e. your Product one) does not fire at all.
I can fix this by changing the *[@isDoc] match to *[name() != 'EventsItem'][@isDoc], but then obviously you ONLY get the item specific template macthing, which may not be what you want. At any rate, there is definitely a matching issue going on here.
As both your templates with match your Product and my EventItem nodes, the matching engine will choose the template with the highest priority. As far as I can tell from the rules, matching by name has a priority of 0, but matching by specific attribute (@isDoc) has a priority of 0.5, so the *[@isDoc] template will always be the one used.
You can see this by adding priority="1" to you match="Product" template - that will give the same behaviour as explicitly excluding those nodes by name as in my last post. If you want to do more hierarchical processing you will have to rethink your original selector, as the descendant-or-self is flattening everything.
Good detective work, Rob - I may have been quite sleepy myself, when I posted that answer :-)
Depending on the scenario, I actually tend to downgrade the generic template (by setting priority="-1") - otherwise I'll have to add the priority attribute to all future DocType templates.
thanks for the help guys, i have added the below with no effect. Is the priority =-1 on the default template match ="/" not where i have put it? Im wondering if my layout is causing some issues as the xlst is pulled directly into a master template and i am just listing all the pages for the slideshow.
first slide (master template which includes xslt macro ) ---table of contents -----------slide 1--- ( i want to display the child nodes in this page) ---------------------product 1 ---------------------product 2 ---------------------product 3 -----------slide 2--- -----------slide 3--- -----------slide 4---
<xsl:template match="/"> <!-- In here, / refers to the rootnode of the <macro> XML document... --> <!-- So we need to get into the Umbraco XML using $currentPage as a starter. --> <!-- Here, we take all descendants of the current page --> <xsl:apply-templates select="$currentPage/descendant-or-self::*[@isDoc][not(umbracoNaviHide = 1)]" /> </xsl:template> <!-- Match any Umbraco DocumentType --> <xsl:template match="*[@isDoc]" priority="-1"> <!-- Do something with it --> <!--<xsl:value-of select="@nodeName"/>--> <!-- Process any <Product> childnodes --> <xsl:apply-templates select="Product" /> </xsl:template> <xsl:template match="Product" priority="1"> <!-- Hey - we found a Product node --> <p> I'm a Product </p> </xsl:template>
Hey guys, ive got the basis of my code working, only thing is when i try to get the child elements of the slide page i get all the child elements of all the slide pages. is there a way only to get the children of that parent page?
first slide (master template which includes xslt macro ) ---table of contents -----------slide 1---( i want to display the child nodes inthis page) ---------------------product 1 ---------------------product 2 ---------------------product 3 -----------slide 2--- -----------slide 3--- -----------slide 4---
<xsl:template match="/"> <!-- Here, we take all descendants and self (landing page) of the pages--> <xsl:apply-templates select="$currentPage/descendant-or-self::*[@isDoc and @level <= $maxLevelForSitemap][not(umbracoNaviHide = 1)]" /> </xsl:template>
<!-- Match any Umbraco DocumentType --> <xsl:template match="*[@isDoc]"> <xsl:choose> <xsl:when test ="local-name() = 'cover_doc'">
The apply-templates instruction rteally makes stuff like this very easy - try this:
1. Create a template that matches your "Product" doctype and render a single item in it, e.g.:
<!-- This will run for every <product_doc> childnode of a <slide1_doc> -->
<xsl:template match="product_doc">
<div class="productslide">
<xsl:value-of select="@nodeName" />
...
</div>
</xsl:template>
2. "Call" it like this from the parent element:
<xsl:when test="self::slide1_doc">
<li data-url="{@nodeName}" >
<div class="slide">
<h1><xsl:value-of select="@nodeName"/></h1>
<!-- Process <product_doc> children -->
<xsl:apply-templates select="product_doc" />
</div>
</li>
</xsl:when>
Thanks Chriztian i added priority="1" to product_doc template match and it all works!! thanks :)
is it possible to use the following if I ever wanted to use apply templates multiple times to filter results? or is it better to create separate doc types?
Yes you can - it all depends really - e.g., in the example you've posted you're duplicating the <li data-url="..."> for every type (you're also generating the same output though, but that's probably just simplified for the example) - I would probably have created seperate templates for each of the different doctypes; I generally avoid a choose/when/otherwise like the plaque. I firmly believe they made it that ugly so you'll always see it as a flag that something is not quite as it should be :-)
I Have 2 pages calling the same template match. What i would like to do is show a different image per page, i could do this in css but at this stage it would be easier if i could query the parent ID name. Ive tried the below but it doesnt work. Any ideas?
Also is it possible to put a position count on doctypes. I have a slider which has 15 pages, 4 of the 15 are using a certain doctype. Can add a class to my doc type like below?
xslt dilemma
hey guys, im creating a online jquery slideshow using umbraco and have come across some things i am unsure of. I have a layout like below, I have a master template which has a xslt which shows all the slides by $currentPage/descendant-or-self::* However i would like one of my pages to display the 3 child elements which contain information about product etc. My slidehow has a structure like below
What is the best way to call these pages? Can i do this via apply template or is it worth including external xslt files? Below is what i have as a starting point.
Hi Graeme,
You don't even need to test if you're on 'Slide 1' - what if you decide to put products under another one next week?
Using apply-templates it all just works - when you say <xsl:apply-templates select="product" /> , the processor will collect all <product> elements under the current node, if there ain't any, nothing will happen - tada! :-)
/Chriztian
hey Christian, that is a good point about the slide 1.
I cant seem to get the below to show, is the below enough for example if i include bodyText from those pages or do i have to put currentpage/product?
Hi Graeme,
Could be a couple of things, most likely due to CasE-sENsitivitY - on the face of it, I'd say your product ought to be Product if it's a seperate DocumentType (lowercase elements are almost always properties.) - so:
/Chriztian
Thanks for the reply chriztan, i think i was half asleep when i replied last night. I still cant get the template match to work, My site structure is more like below, i forgot to include the table of contents
I changed my doc type and it hasnt made a difference
Are you sure you are actually where you think you are in the document tree?
I would stick this in at the top:
<xmp><xsl:copy-of select="$currentPage"/></xmp>
Then you can assure yourself that $currentPage is what you think it is.
And maybe count() your first selector to check it's matching correctly, too.
Actually, ignore that, I have just done a quick test and am gettign no output either, I'll get back to you :o)
Okay, the template matching *[@isDoc] seems to be preventing the Product template from matching. I'm still not 100% sure about where in your structure you are using this, so maybe this is not entirely relevant, but if I have the structure:
EventsPage
---EventsItem
---EventsItem
---EventsItem
...and with $currentPage as EventsPage print out name() from the *[@isDoc] template, I get:
EventsPage
EventsItem
EventsItem
EventsItem
...but the EventsItem specific template (i.e. your Product one) does not fire at all.
I can fix this by changing the *[@isDoc] match to *[name() != 'EventsItem'][@isDoc], but then obviously you ONLY get the item specific template macthing, which may not be what you want. At any rate, there is definitely a matching issue going on here.
http://msdn.microsoft.com/en-us/magazine/cc164105.aspx (search with page for "conflict resolution")
As both your templates with match your Product and my EventItem nodes, the matching engine will choose the template with the highest priority. As far as I can tell from the rules, matching by name has a priority of 0, but matching by specific attribute (@isDoc) has a priority of 0.5, so the *[@isDoc] template will always be the one used.
You can see this by adding priority="1" to you match="Product" template - that will give the same behaviour as explicitly excluding those nodes by name as in my last post. If you want to do more hierarchical processing you will have to rethink your original selector, as the descendant-or-self is flattening everything.
Good detective work, Rob - I may have been quite sleepy myself, when I posted that answer :-)
Depending on the scenario, I actually tend to downgrade the generic template (by setting priority="-1") - otherwise I'll have to add the priority attribute to all future DocType templates.
/Chriztian
Are yes, good point. That's why you're an XSLT guru and I'm merely a gifted grasshopper ;o)
thanks for the help guys, i have added the below with no effect. Is the priority =-1 on the default template match ="/" not where i have put it? Im wondering if my layout is causing some issues as the xlst is pulled directly into a master template and i am just listing all the pages for the slideshow.
I'm still unable to show to show child elements in each of my slide pages, any ideas?
Hey guys, ive got the basis of my code working, only thing is when i try to get the child elements of the slide page i get all the child elements of all the slide pages.
is there a way only to get the children of that parent page?
below is my code. thanks
Hi Graeme,
The apply-templates instruction rteally makes stuff like this very easy - try this:
1. Create a template that matches your "Product" doctype and render a single item in it, e.g.:
/Chriztian
apply-templates FTW!
Thanks Chriztian i added priority="1" to product_doc template match and it all works!! thanks :)
is it possible to use the following if I ever wanted to use apply templates multiple times to filter results? or is it better to create separate doc types?
thanks again! :)
Graeme
Hi Graeme,
Yes you can - it all depends really - e.g., in the example you've posted you're duplicating the <li data-url="..."> for every type (you're also generating the same output though, but that's probably just simplified for the example) - I would probably have created seperate templates for each of the different doctypes; I generally avoid a choose/when/otherwise like the plaque. I firmly believe they made it that ugly so you'll always see it as a flag that something is not quite as it should be :-)
/Chriztian
I Have 2 pages calling the same template match. What i would like to do is show a different image per page, i could do this in css but at this stage it would be easier if i could query the parent ID name. Ive tried the below but it doesnt work. Any ideas?
Also is it possible to put a position count on doctypes. I have a slider which has 15 pages, 4 of the 15 are using a certain doctype. Can add a class to my doc type like below?
1 blah_doc
2 me_doc (1)
3 me_doc (2)
4 me_doc (3)
5 hello_doc
is working on a reply...