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 2800 posts 8791 karma points MVP 8x 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 2800 posts 8791 karma points MVP 8x 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

Please Sign in or register to post replies

Write your reply to:

Draft