Copied to clipboard

Flag this post as spam?

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


  • David 26 posts 50 karma points
    Sep 06, 2010 @ 12:30
    David
    0

    Sorting on two values (when one is an override)

    I "think" this is a bit of a tricky one - however I'm sure the rocket scientists here already have a solution :)

    In our Umbraco rollouts - we give the administrators the ability override the node node-name in navigation.  This allows administrators to keep the URL/name intact when you are on-page, but allows a shorter name to be used as part of a navigation taxonomy.

    For example, I may have a page named "How to tie your shoe laces", however the navigation text for this item may be shortened "Tie shoe laces". (hope this makes sense).

    This is all well and good, however I have the issue of ording navigation nodes if this feature is used on "some" but not "all" nodes. The following table illustrates this issue:

    ID  /  Node Name  /  Text override  /  Name Displayed
    1  /  A  /  Y  /  Y
    2  /  B  /  X  /   X
    3  /  C  /      /  C
    4  /  D  /  Z  /   D

    I would like the data to be sorted as follows:
    3  /  C  /      /  C
    2  /  B  /  X  /   X
    1  /  A  /  Y  /  Y
    4  /  D  /  Z  /   Z

    Desired Sort
    The sort that I am looking for is that the nodes are sorted firstly by "Text override" (if entered) and then by "Node Name".  In c# I would achieve this with a coalesce(textOveride,NodeName), however within the xslt environement and the simple "sort" element I cannot work out how this would be achieved.

    I appreciate my query is very specific to overiding the node-name on navigation; however I can think of many other situations where ordering by multiple fields (optionally completed) would be extremely useful.

    Many thanks for your help in adance,
    David :-)

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Sep 06, 2010 @ 15:16
    Chriztian Steinmeier
    0

    Hi David,

    Hint: You can add as many sort elements inside an apply-templates (or for-each) instruction as you like...

    (If that's not enough let us know :-)

    /Chriztian

  • David 26 posts 50 karma points
    Sep 06, 2010 @ 16:11
    David
    0

    Hi Chriztian,

     

    Thanks for coming back to me.

    Unfrotuantely I have already tried this using both apply-template and for-each.  I have also confirmed that I am querying the correct fields by outputting both the nodeName and textOverride values.  Unfortunately the nodes without a textOverride are all sorted together, for example...

    Sort using two sort nodes
    ID  /  Node Name  /  Text override  /  Name Displayed
    2  /  B  /  X  /   X
    1  /  A  /  Y  /  Y
    4  /  D  /  Z  /   Z
    5  /  E  /      /  E     <----  These two fields go to the end as their text override is blank
    3  /  C  /      /  C     <----  ~~~~~~~~~~~~~~~~~~~ " ~~~~~~~~~~~~~~~~~~~~~~~

    Hope this makes sence with my ASCII art table :-)

  • Hendrik Jan 71 posts 137 karma points
    Sep 06, 2010 @ 16:34
    Hendrik Jan
    0

     

    If overide is blanc use nodename ?

    <xsl:sort select="menuTitle | @nodeName [menuTitle = '']" order="ascending" />
  • David 26 posts 50 karma points
    Sep 06, 2010 @ 17:16
    David
    0

    Hi Niels,

    Thanks for the reply.

    Unfortunately I coulndt undersatnd your reply - but it got me thinging about concatenating in the sort node itself.

    I'm pretty sure that the following code is now working for me:

    <xsl:sort select="concat(./data[@alias='mkNavText'],@nodeName)" /> 


    Simply - this makes a string of the override text + the actual nodeName, e.g. nodeName versus TextOverrideNodeName.

    Let's see how this plays out in the example I have given above...

    ID  /  NodeName  /  TextOverride  / ConCat(TextOverride,NodeName)
    3  /  C  /      /  C
    5  /  E  /      /  E
    2  /  B  /  X  /  XB
    1  /  A  /  Y  /  YA
    4  /  D  /  Z  /  ZD

    PERFECT !!!!   :)    

    Please let me know if there is a better way of doing this or if this helps you at all.  I'm hoping that this little technique will help anyone who needs to sort by two textual valuals where one is an override of the other.

    Kind regards,
    David

  • Hendrik Jan 71 posts 137 karma points
    Sep 06, 2010 @ 17:39
    Hendrik Jan
    0

    Hey David,

    Good thing u got ya code running.

    The most clean solution would be this:

    <xsl:sort select="data[@alias='mkNavText'] | @nodeName [current()/data[@alias='mkNavText'] = '']"/>

     

     

     

  • David 26 posts 50 karma points
    Sep 06, 2010 @ 17:54
    David
    0

    Hi Niels,

    That's better than PERFECT - thank you so much.

    My, frankly less than perfect, solution above was definately not ideal and would actually have sorting issues when concatenating short words.

    I would  be very interested in understanding exactly how that syntax works... as my predicates didn't seem to work.  I suspect this was becuase I had nested predicates like this...

    <xsl:value-of select="./data[@alias='mkNavText'] [ ./data[@alias='mkNavText']!='' ] | @nodeName [ ./data[@alias='mkNavText']='' ]"/>

    I'm marking your reply as the solution now, but if you don't mind - could you explain your elegant syntax to me?

    Thank you again so much for you help,
    David (happy)

  • Hendrik Jan 71 posts 137 karma points
    Sep 06, 2010 @ 18:08
    Hendrik Jan
    2

    Ok i wil try:

    the " | " character will take the value left and value right and add it to a node-set, so it becomes like this:

    <nodeset>
       <value>data[@alias='mkNavText']<value>
       <value>@nodeName [current()/data[@alias='mkNavText'] = '']</value>
    </nodeset>

    but the [current()/data[@alias='mkNavText'] = ''] will make sure the @nodeName will only be selected if data[@alias='mkNavText'] is empty. Now you only get 1 result!  the override or the nodename.

    (it does not really make a <nodeset> structure, its for illustrational purposes)



    What u did wrong was your xpath selecor:

    @nodeName [ ./data[@alias='mkNavText']='' ]

    this wil look for:

    $page/  data[@alias='mkNavText']/data[@alias='mkNavText'] &
    $page/  @nodeName/data[@alias='mkNavText']
    So in stead of the ./data i refer to current()/data. the current() references to the current item in the for-each loop

    @nodeName [ ./data[@alias='mkNavText']=''"]     =       $page/  @nodeName/data[@alias='mkNavText']

    &
    @nodeName [ current()/data[@alias='mkNavText']='' ]   = $page /data[@alias='mkNavText']

  • Rob Watkins 369 posts 701 karma points
    Jan 04, 2012 @ 11:25
    Rob Watkins
    0

    Fantastic, Niels, this just saved me a lot of hair tearing!

Please Sign in or register to post replies

Write your reply to:

Draft