Press Ctrl / CMD + C to copy this to your clipboard.
This post will be reported to the moderators as potential spam to be looked at
Having a heck of a time with some basic xslt in the new 4.5 schema.
Trying to convert this code:
"$currentPage", "//node[@id='" + currentNodeId + "']")
to work under the new schema. What's the correct syntax for node selection by id under the new schema?! Trying to tweak the Axenda Ultimate Picker XPath to work using the new schema.
$currentPage//*[@isDoc and @id=$currentNodeId]
Is this right?
In the new XML schema, there is no such thing as the node. In the new schema the nodes are named after which documenttype used by the node.
So instead of node you'll write * (if you want to select nodes of different document types). If the node is a document, the're is a new attribute called isDoc attached in the XML.
So instead of:
you can write:
When I try to do something like:
*[@isDoc and @id = '1067']/@nodeName
via the xslt evaluator to just show the node name for a specific node when I know the id, I get no results.
I'm basically trying to do the same thing as $currentPage but using only xpath. I need to update the axenda ultimate picker source logic to use the new schema syntax. The current version takes the //node [...] approach to replacing $currentPath which is of course the old schema.
If you're replacing $currentPage (as in the example you start with) you should be able to do:
Replace("$currentPage", "//*[@isDoc][@id = " + currentNodeId + "]")
(apostrophes from original example not really needed).
Why does this work:
<xsl:for-each select="umbraco.library:GetXmlNodeById(1067)/*[@isDoc]"><xsl:value-of select="./@nodeName"/><br/></xsl:for-each>
....but this does not:
<xsl:for-each select="//*[@id=1067]/*[@isDoc]"><xsl:value-of select="./@nodeName"/><br/></xsl:for-each>
...when trying to test/view the output using the xslt visualizer?
It all comes down to context and the concept of what's called "the current node" in XSLT and XPath - not to be confused with the Umbraco parameter "$currentPage".
Whenever an XPath expression gets evaluated, there's a current node context that the axes, locations steps and predicates are working against - in the case of the first example, you're creating a new context with the GetXmlNodeById() function, so the following "/*[@isDoc]" works on that context.
In the second example there's only an implicit context, which is whatever was the current node before the <xsl:for-each> instruction. It's a bit tricky to explain, but because the XPath expression starts with a double slash (//) it will search the *whole* XML document from the top - but *that* document, is the document that contains the current node, and here's the problem: When XSLT macros run in Umbraco, the actual document that it gets to work on is a simple XML document that looks something like this:
<!-- More parameters here -->
So the initial template (<xsl:template match="/">) will start with that document, which doesn't give us much...
BUT: The XSLT is provided a parameter (<xsl:param>) with an additional context for us to use, so the way we get to the Umbraco nodes is by way of said $currentPage parameter. This is why you'll see XPath expressions starting with $currentPage to create the current node context needed.
Phew - still here?
That's why the double slash won't work in the XSLT Visualizer - BUT it should work in the C# code you're trying to tweak, because the context document in *that* is most likely the Umbraco XML document nodes (judging from the expression you're replacing).
Hope it helped,
Very helpful! Thanks much that helps me understand why I don't see what I expect in the xslt visualizer. So I think my xpath is correct in my c# code, I just have to figure out why it's not working :( I'll go post in the axendo ultimate picker project and look for suggestions on what I may be doing wrong.
That was a pretty impressive explanation Chriztian - thumbs up!
Remember to mark an answer as the solution if your problem is solved :)
"BUT: The XSLT is provided a parameter (<xsl:param>) with an
additional context for us to use, so the way we get to the Umbraco nodes
is by way of said $currentPage parameter. This is why you'll see XPath
expressions starting with $currentPage to create the current node
so that being said the following would perhaps be acceptable? Calling in this way provides access to the entire site tree which I need in many cases.
<xsl:variable name="home_id" select="1048" /> <!--should be your site root id--> <xsl:variable name="site_root" select="umbraco.library:GetXmlNodeById($home_id)" /> <xsl:template match="/"> <xsl:for-each select="$site_root/*"> <xsl:value-of select="./@nodeName"/><br/> </xsl:for-each> </xsl:template>
Oh, but the beauty of $currentPage is that you have access to the entire site - you're given that whole document but the 'handle' is set at the page currently being rendered. It's so great because 80% of the time that's your focus - you want to do stuff with that node and its children, sometimes the parent; and then there's the other 20% where you need to research the rest of the structure to get the info you want. It's immensely powerful.
OK, on to your code - that'll work, but there's a simpler and already kind of "de facto" way of doing that: To get the root node of the XML document, which is incidentally called "root" you just add this variable after the currentPage param:
<xsl:variable name="contentRoot" select="$currentPage/ancestor-or-self::root" />
There's only ever going to be one element in the ancestor axis calle "root", so it's safe to do this (you need "-or-self" here because Umbraco will set $currentPage to the rootnode when saving the XSLT file, to test for validation errors).
If you have a multi-site setup where all the nodes at level 1 are "Home" nodes, you do this:
<xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
- so no need to call the library for that; The asterisk (*) makes it work in both the old and the new schema, and the level predicate filters out all the other ancestors so you end up with only the one you need.
Hope this helps you,
PS: @Kim - thanks! :-)
ok sounds good, I also looked in the library function reference and found GetXmlNodeByXPath which is exactly what I want. [GetXmlNodeByXPath('/root')] I actually started using this after my last post... is this call slower than traversing backwards through the XML via ancestor-or-self with a filter?
In my experience 80% of the time the curent page node itself isn't necessarily the most important node for delivery - it's only a key to resolve assets associated with a particular url - of which there may be many. e.g.; news feeds, image galleries, related content blocks, people, etc. So having a $currentPage reference is nice but not as nice as simply having the freedom of moving throughout the entire document to collect references that may be associate to the requested node.
is working on a reply...
Write your reply to:
Image will be uploaded when post is submitted