Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • KsuValk 32 posts 52 karma points
    Aug 01, 2010 @ 04:47
    KsuValk
    0

    New Schema Select Node by Id

    Having a heck of a time with some basic xslt in the new 4.5 schema. 

    Trying to convert this code:

     

     

    xpath.Replace(

     

    "$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.

    Thx

     

     

  • sun 403 posts 395 karma points
    Aug 01, 2010 @ 08:58
    sun
    0

    $currentPage//*[@isDoc and @id=$currentNodeId]

    Is this right?

  • Kim Andersen 1447 posts 2196 karma points MVP
    Aug 01, 2010 @ 12:25
    Kim Andersen
    1

    Hi KsuValk

    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:

    node

    you can write:

    *[@isDoc]

    /Kim A

  • KsuValk 32 posts 52 karma points
    Aug 02, 2010 @ 15:11
    KsuValk
    0

    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.

     

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Aug 02, 2010 @ 15:38
    Chriztian Steinmeier
    0

    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). 

    /Chriztian

  • KsuValk 32 posts 52 karma points
    Aug 03, 2010 @ 03:05
    KsuValk
    0

    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?

     

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Aug 03, 2010 @ 09:12
    Chriztian Steinmeier
    7

    Hi KsuValk,

    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:

    <macro>
        <macroParameter>Value</macroParameter>
        <!-- More parameters here -->
    </macro>

    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,

    /Chriztian

  • KsuValk 32 posts 52 karma points
    Aug 03, 2010 @ 15:14
    KsuValk
    0

    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.

    Thanks much!

     

  • Kim Andersen 1447 posts 2196 karma points MVP
    Aug 03, 2010 @ 18:23
    Kim Andersen
    0

    That was a pretty impressive explanation Chriztian - thumbs up!

    @KsuValk:

    Remember to mark an answer as the solution if your problem is solved :)

  • montana 42 posts 63 karma points
    Aug 16, 2010 @ 21:19
    montana
    0

    @Chriztian

    "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."

    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>
  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 8x admin c-trib
    Aug 16, 2010 @ 23:22
    Chriztian Steinmeier
    1

    @montana

    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,

    /Chriztian

    PS: @Kim - thanks! :-)

  • montana 42 posts 63 karma points
    Aug 17, 2010 @ 20:42
    montana
    0

    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.

Please Sign in or register to post replies

Write your reply to:

Draft