Copied to clipboard

Flag this post as spam?

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


  • Thomas Kahn 602 posts 506 karma points
    Nov 27, 2009 @ 16:19
    Thomas Kahn
    0

    Print to screen only when a value is different from the preceding value?

    Hi!

    Let's say I have an XML-structure that looks like this:

    <person>
    <name>Jakob</name>
    <title>Art Director</title>
    </person>

    <person>
    <name>Lea</name>
    <title>Art Director</title>
    </person>

    <person>
    <name>Jonas</name>
    <title>Project Manager</title>
    </person>

    <person><name>Thomas</name>
    <title>Web Developer</title>
    </person>

    <person>
    <name>Johan</name>
    <title>Web Developer</title>
    </person>

    Using XSLT I print these persons using a for-each loop. I want the name of the person to be printed every time, but I want to use the title as a header to group the persons I'm listing. The result I want on the screen is:

    Art Director
    Jakob
    Lea

    Project Manager
    Jonas

    Web Developer
    Thomas
    Johan

    How would I accomplish this using XSLT? Is there a way to track if the present value in the loop is different from the previous value and if it is, print it to screen. I suspect the solution involves using calling another template, but I'm having a hard time finding the best solution.

    Thanks in advance!

    /Thomas Kahn

  • Bert 128 posts 251 karma points
    Nov 27, 2009 @ 16:43
    Bert
    0

    Can't you adapt the data structure?

    <function name="Web Developer">
    <person name="Johan" />
    <person name="Sam" />
    </function>
    <function ... </function>
  • bob baty-barr 1180 posts 1294 karma points MVP
    Nov 27, 2009 @ 17:15
    bob baty-barr
    0

    you could run a nested for each... where you list the <title> when the position is equal to 1

    then insided that for each list the <name> where title = currentTitle --

    hope that makes sense.

  • Chriztian Steinmeier 2726 posts 8320 karma points MVP 4x admin c-trib
    Nov 27, 2009 @ 21:58
    Chriztian Steinmeier
    1

    Hi Thomas,

    If your data is already sorted by title (which your short fragment suggests) then the following template will be sufficient:

       <xsl:template match="person">
            <xsl:if test="preceding-sibling::person[1]/title != title or not(preceding-sibling::person[1])">
                <h2>
                    <xsl:value-of select="title" />
                </h2>
            </xsl:if>
            <p>
                <xsl:value-of select="name" />
            </p>
        </xsl:template>
    

     

    If that's not the case, you'll have to dive into "grouping" which can be quite a hassle in XSLT 1.0... let us know, if so.

    /Chriztian

  • Thomas Kahn 602 posts 506 karma points
    Nov 27, 2009 @ 22:21
    Thomas Kahn
    0

    Chriztian, I think your example could work! The nodes are not sorted in any specific order in Umbraco, but in the XSLT I sort them by title and that should be enough.

    Will try it first thing on Monday!

    /Thomas

  • Thomas Kahn 602 posts 506 karma points
    Nov 30, 2009 @ 10:48
    Thomas Kahn
    0

    Chriztian - you just saved me a lot of headaches!
    It worked like a charm - thanks!

    /Thomas K

  • Thomas Kahn 602 posts 506 karma points
    Nov 30, 2009 @ 11:29
    Thomas Kahn
    0

    Hmm, I guess I jumped the gun there.
    This solution works if the nodes are ordered in the correct order in the umbraco backend. In my case they are not - I use a sort select in my XSLT to sort the nodes in the correct order.

    So it seems that preceding-sibling::node[1] ignores any sorting directives in the XSLT and uses the order the nodes have in Umbraco.

    Bummer. Is there a way to get around this?

    /Thomas Kahn

  • Thomas Kahn 602 posts 506 karma points
    Nov 30, 2009 @ 12:05
    Thomas Kahn
    0

    This was new to me:

    "The axis works on the XML source's internal tree-representation (the XSLT processor builds the tree before applying a stylesheet). Therefore,
    when you say "xsl:sort", it just begins to process the nodes in the order you specify, sorting can't affect any axis processing."

    http://p2p.wrox.com/xslt/3040-sorting-preceding-sibling.html

    This page contains a suggestion how to solve the problem by copying the sorted nodes to a new node set. In my code it looks like this:

    <xsl:variable name="sortedNodeSet">
    <xsl:for-each select="$currentPage/descendant::node">
    <xsl:sort select="data[@alias='competitionStatus']" order="descending"/>
    <xsl:sort select="@nodeName" order="ascending"/>
    <xsl:copy-of select="."/>
    </xsl:for-each>
    </xsl:variable>

    I can print values from this new nodeset using:

    <xsl:value-of select="$sortedNodeSet"/>

    ...but as soon as I try something like this:

    <xsl:for-each select="$sortedNodeSet/*">
    <xsl:value-of select="@nodeName"/>
    </xsl:for-each>

    ...I get Error parsing XSLT file.

    Has anyone done this before in umbraco? If so, any clues how I can accomplish this?

    Thanks in advance!
    /Thomas K

  • Thomas Kahn 602 posts 506 karma points
    Nov 30, 2009 @ 12:16
    Thomas Kahn
    0

    Answering my own question: it seems like the result from the first for-each loop is not really a nodeset, but something called a tree fragment. In order to make it a nodeset you need to use exslt:node-set, like this:

    <xsl:for-each select="exslt:node-set($sortedNodeSet)/*">
    <xsl:value-of select="@nodeName"/>
    </xsl:for-each>

    You will also need to add the namespace to the stylesheet. I added xmlns:exslt="http://exslt.org/common" in my stylesheet.

    After having done this, it works like expected (so far)!

    This is totally new to me so I'd love any input or improvements on this.

    /Thomas K

     

  • Chriztian Steinmeier 2726 posts 8320 karma points MVP 4x admin c-trib
    Nov 30, 2009 @ 23:41
    Chriztian Steinmeier
    0

    Hi Thomas,

    Oh yes - that's why I said "If your data is already sorted by title", because this was the easy solution :-)

    I'm a little uncertain if you've solved your problem using the node-set() function? (Incidentally, the function is already available in Umbraco as either msxml:node-set() or Exslt.ExsltCommon:node-set())

    If you're still looking for a solution you should check out (i.e. google for) 'grouping' and 'muenchian' for the gory details... (or ask for an example)

    /Chriztian

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies