Copied to clipboard

Flag this post as spam?

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


  • Daniel Nøhr 14 posts 35 karma points
    Oct 14, 2009 @ 15:36
    Daniel Nøhr
    0

    How to merge node results sets

    Hello

    Is it possible to merge/copy two or more node results sets together, or do I need another solution?

    I have tried searching on the web, but didn't have any luck for my specific solution.

    Here is my code..

    <xsl:variable name="inputStr">test1,test2,test3</xsl:variable>

    <xsl:for-each select="Exslt.ExsltStrings:split($inputStr, ',')">
        <xsl:variable name="str" select="text()"/>
        <xsl:for-each select="$pages [contains((data [@alias = 'tags']), $str)]">
            // !!! I need something like a container to put my item in here..
        </xsl:for-each>
    </xsl:for-each>

    The code works fine, but I don't know how to put my two og more sets together, and then make a top 10 limit.

  • dandrayne 1138 posts 2262 karma points
    Oct 14, 2009 @ 17:18
    dandrayne
    0

    Is this by any chance to create a list of unique tags from comma separated tag data for particular nodes?  I had a similar problem a few months back -> http://forum.umbraco.org/yaf_postst9763_Getting-a-unique-list-from-comma-separated-values-in-xslt.aspx.

    Annoyingly I didn't come up with a solution back then.  Even more annoyingly, I've just come up to a part in a project where I need to do just this.  I'll give it another shot and post back here if I get a solution.

    If this has nothing to do with your problem then just ignore me!

    Dan

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Oct 14, 2009 @ 17:59
    Morten Bock
    1

    Well, you can create a nodeset like this:

    <xsl:variable name="myValues">
        <values>
            <value>13</value>
            <value>22</value>
            <value>23</value>
            <value>30</value>
            <value>40</value>
        </values>
    </xsl:variable>
    <xsl:variable name="myNodeset" select="msxsl:node-set($myValues)">
    <xsl:for-each select="$myNodeset/values/value">
    ....
    </xsl:for-each>

    And I think that somewhere in the Exslt extensions there is a method for combining two sets of nodes

  • Daniel Nøhr 14 posts 35 karma points
    Oct 15, 2009 @ 14:41
    Daniel Nøhr
    0

    dandrayne

    Yes, as far I can read, It look likes you got the same problem, but you didn't make it work somehow back then?

    Morten Bock

    Thanks for your example, but still can't resolve the problem, or just don't know how to do it, have been trying searching for a working combining method without any luck..

     

    Here is an example of my research, maybe you can get this one work, I couldn't.

    http://www.stylusstudio.com/xsllist/200503/post91390.html

    Please share, if any of you find or got a solution on this problem. Otherwise i can't make my "Related blogs" based on tags :-)

  • Jacob Jensen 29 posts 49 karma points
    Oct 15, 2009 @ 15:40
    Jacob Jensen
    0

    I dont really know what your are trying to accomplish, but following mortens example, maybe this is usefull

     

    <!--

     

    Creating fake content to $pages-->

    <

     

    xsl:variable name="pages">

    <

     

    root>

    <

     

    node id="342"></node>

    <

     

    node id="435"></node>

    <

     

    node id="436"></node>

    <

     

    node id="453"></node>

    <

     

    node id="4235"></node>

    <

     

    node id="34"></node>

    <

     

    node id="242"></node>

    <

     

    node id="42"></node>

    <

     

    node id="436"></node>

    <

     

    node id="342"></node>

    <

     

    node id="435"></node>

    <

     

    node id="436"></node>

    </

     

    root>

    </

     

    xsl:variable>

    <

     

    xsl:variable name="inputStr">342,453,436</xsl:variable>

     

    <!--

     

    Your working example-->

    <

     

    xsl:variable name="selectedPages">

    <

     

    root>

    <

     

    xsl:for-each select="Exslt.ExsltStrings:split($inputStr, ',')">

     

    <

     

    xsl:variable name="str" select="text()"/>

     

    <

     

    xsl:for-each select="msxml:node-set($pages)/root/node[contains(@id, $str)]">

    <

     

    xsl:variable name="id" select="@id" />

    <

     

    xsl:copy-of select="."/>

    </

     

    xsl:for-each>

    </

     

    xsl:for-each>

    </

     

    root>

    </

     

    xsl:variable>

     

     

    <!--

     

    distinct on @id-->

    <

     

    xsl:variable name="distinctPages">

    <

     

    root>

    <

     

    xsl:for-each select="msxml:node-set($pages)/root/node[not(@id = preceding-sibling::node/@id)]">

    <

     

    xsl:copy-of select="."/>

    </

     

    xsl:for-each>

    </

     

    root>

    </

     

    xsl:variable>

     

    <!--

     

    selected and distinct pages -->

    <

     

    xsl:variable name="disSelPages">

    <

     

    root>

    <

     

    xsl:for-each select="msxml:node-set($selectedPages)/root/node[not(@id = preceding-sibling::node/@id)]">

    <

     

    xsl:copy-of select="."/>

    </

     

    xsl:for-each>

    </

     

    root>

    </

     

    xsl:variable>

    <!--

     

    Merging the 2 results - Distinct and Selected-->

    <

     

    xsl:variable name="both">

    <

     

    root>

    <

     

    xsl:for-each select="msxml:node-set($selectedPages)/root/node">

    <

     

    xsl:copy-of select="."/>

    </

     

    xsl:for-each>

    <

     

    xsl:for-each select="msxml:node-set($distinctPages)/root/node">

    <

     

    xsl:copy-of select="."/>

    </

     

    xsl:for-each>

    </

     

    root>

    </

     

    xsl:variable>

     

    <!--

     

    Top 10, most used id in result -->

    <

     

    xsl:variable name="result">

    <

     

    root>

    <

     

    xsl:for-each select="msxml:node-set($both)/node">

    <

     

    xsl:sort case-order="lower-first" select="@id"/>

    <

     

    node>

    <

     

    xsl:attribute name="id">

    <

     

    xsl:value-of select="@id"/>

    </

     

    xsl:attribute>

    </

     

    node>

    </

     

    xsl:for-each>

    </

     

    root>

     

    </

     

    xsl:variable>

     

    <

     

    textarea style="width: 100%;height: 500px;" xml:space="preserve">

    All:

    <

     

    xsl:copy-of select="msxml:node-set($pages)"/>

     

    Selected:

    <

     

    xsl:copy-of select="msxml:node-set($selectedPages)" />

     

    Distinct:

    <

     

    xsl:copy-of select="msxml:node-set($distinctPages)"/>

     

    Distinct and selected

    <

     

    xsl:copy-of select="msxml:node-set($disSelPages)" />

     

    Both

    <

     

    xsl:copy-of select="msxml:node-set($both)"></xsl:copy-of>

     

    Top 3

    <

     

    xsl:copy-of select="msxml:node-set($result)"/>

    </

     

    textarea>

     

    Else, please supply some xml, or describe further

    /Jacob

  • dandrayne 1138 posts 2262 karma points
    Oct 15, 2009 @ 15:43
    dandrayne
    1

    Hi Daniel

    This time I didn't have a choice, so I enlisted a bit of help from another guy in the office.  Below I've included the xslt with a c# function that's working fine for me.  I've added comments, just in case.

    Note:  This xslt is used for getting a list of all tags attached to uploaded files in a chosen folder of the media library, then displaying the tags in a list of uniques, each with the amount of times the tag appears recorded.  It will be easily changed to apply to anywhere else you have used tags.

    It's probably also worth mentioning that in this case I'm not using the "tags" datatype (it seems a bit flakey) and the tags are just comma separated values in a string.

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE xsl:stylesheet [
    <!ENTITY nbsp "&#x00A0;">
    ]>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxml="urn:schemas-microsoft-com:xslt"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:umbraco.library="urn:umbraco.library"
    xmlns:ps="urn:percipientstudios-com:xslt"
    xmlns:gecko="urn:gecko-com:xslt"
    exclude-result-prefixes="msxml umbraco.library ps gecko">

    <xsl:output method="xml" omit-xml-declaration="yes" />


    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <xsl:param name="currentPage"/>

    <xsl:template match="/">

    <!-- Grab currently requested tag and save as variable 'filter' -->
    <xsl:variable name="filter">
    <xsl:choose>
    <xsl:when test="string-length(umbraco.library:Request('tag')) &gt; 0">
    <xsl:value-of select="umbraco.library:Request('tag')"/>
    </xsl:when>
    <xsl:otherwise>
    <xsl:text>all</xsl:text>
    </xsl:otherwise>
    </xsl:choose>
    </xsl:variable>

    <!-- Does the currentpage have a chosen media folder? (using mediaPicker with alias documentMediaFolder) -->
    <xsl:if test="string($currentPage/data [@alias='documentMediaFolder']) != ''">

    <!-- get the actual media node from the ID using getMedia -->
    <xsl:variable name="mediaFolder" select="umbraco.library:GetMedia($currentPage/data [@alias='documentMediaFolder'], 'true')" />

    <!--
    Build up a master list of tags for all documents within the selected folder

    finished string will be of format: tag,tag2,tag,tag3,tag2,tag etc etc
    -->
    <xsl:variable name="mediaFolderTags">
    <xsl:for-each select="$mediaFolder/node [string(data[@alias='fileTags']) != '']"><xsl:value-of select="current()/data[@alias='fileTags']" />,</xsl:for-each>
    </xsl:variable>

    <!--
    pass our list of comma separated tags to our DistinctValues function

    This function returns xml of the format below, with unique tags and an attrubute showing the frequency with which the tag appears

    <values>
    <value count="1">tagname</value>
    <value count="3">tagname2</value>
    </values>
    -->
    <xsl:variable name="resultSet" select="gecko:DistinctValues($mediaFolderTags)" />


    <!-- just some stuff for a header and a "show all documents" link -->
    <h4 class="document_tags"><span>Filter by tags</span></h4>

    <ul class="all_tags">

    <li>
    <xsl:if test="$filter= 'all'">
    <xsl:attribute name="class">
    <xsl:text>current</xsl:text>
    </xsl:attribute>
    </xsl:if>
    <a>
    <xsl:attribute name="href">
    <xsl:value-of select="umbraco.library:NiceUrl($currentPage/@id)" />
    </xsl:attribute>
    All
    </a>
    </li>
    <!-- main for-each loop going through the results of our function. note this allows for sorting by frequency (shown below) as well as tag name -->
    <xsl:for-each select="$resultSet//value">
    <xsl:sort select="@count" order="descending" />
    <xsl:sort select="text()" order="ascending" />
    <li>
    <xsl:if test="current()/text() = $filter">
    <xsl:attribute name="class">
    <xsl:text>current</xsl:text>
    </xsl:attribute>
    </xsl:if>
    <a>
    <xsl:attribute name="href">
    <xsl:value-of select="umbraco.library:NiceUrl($currentPage/@id)" />?tag=<xsl:value-of select="current()" />
    </xsl:attribute>
    <xsl:value-of select="current()" />
    <span>
    (<xsl:value-of select="current()/@count" />)
    </span>
    </a>
    </li>

    </xsl:for-each>
    </ul>

    </xsl:if>



    </xsl:template>



    <msxml:script language="CSharp" implements-prefix="gecko">


    <msxml:assembly name="System.Web" />
    <msxml:using namespace="System.Web" />

    <![CDATA[


    public XmlDocument DistinctValues(String commaList) {

    string[] arr = commaList.Split(',');
    var distinctCount = new ArrayList(arr.Length);
    var distinctNames = new ArrayList(arr.Length);

    foreach(string str in arr)
    {
    if(string.IsNullOrEmpty(str))
    {
    continue;
    }
    var index = distinctNames.IndexOf(str);
    if (index >= 0)
    {
    var currentCount = (int)distinctCount[index];
    distinctCount[index] = currentCount + 1;
    }
    else
    {
    distinctNames.Add(str);
    distinctCount.Add(1);
    }
    }

    var outPut = "";
    for (var i = 0; i < distinctNames.Count; i++)
    {
    var name = distinctNames[i];
    var count = distinctCount[i];
    outPut += "<value count='" + count + "'>" + name + "</value>";
    }

    var xml = new XmlDocument();
    xml.LoadXml("<values>" + outPut + "</values>");
    return xml;
    }
    ]]>

    </msxml:script>

    </xsl:stylesheet>

    Good luck,
    Dan

  • Jacob Jensen 29 posts 49 karma points
    Oct 15, 2009 @ 15:47
  • Nik Wahlberg 639 posts 1237 karma points MVP
    Oct 15, 2009 @ 15:50
    Nik Wahlberg
    0

    Daniel,

    it looks like what Morten is suggesting should work. Are you able to loop over your original nodes in several loops? If so, your code might look something like this:

    <xsl:variable name="nodeSetVar">
          <xsl:for-each select="">
            <!-- loop out nodes from first XPath -->
          </xsl:for-each>
          <xsl:for-each select="">
            <!-- loop out nodes from second XPath -->
          </xsl:for-each>
          ...     
        </xsl:variable>
        <xsl:variable name="myNodeset" select="msxsl:node-set($nodeSetVar)"/>
        <xsl:for-each select="$myNodeset/values/value">
          ....
        </xsl:for-each>

    Based on Mortens response above...

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Oct 15, 2009 @ 19:13
    Morten Bock
    0

    Daniel, are you using the tag datatype in umbraco? If your are, then there is actually a small set of library methods for the tags. Even one that gets all content with with a certain tag.

    I am using that on my own blog.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Oct 15, 2009 @ 19:18
    Morten Bock
    0

    It even takes a comma separated string:

    getContentsWithTags('some,tags,here')

  • Daniel Nøhr 14 posts 35 karma points
    Oct 16, 2009 @ 10:45
    Daniel Nøhr
    1

    What a amazing thread we just got here, just perfect - After the example from Nik Wahlberg based on Morten Bock's code, i finally got my very nice solution.

    And thanks Jacob Jensen, you did just help me with a very nice example of how to distinct in a wonderful way trough xslt.

    Morten Bock - Nope, I'm not using the tag feature in umbraco, but my own meta keyword based solution, from my new blog based on umbraco, at dnohr.dk, which works perfect. Didn't used the Blog4Umbraco, because I did have to convert some old blog data from my old website, so it's just a better way to learn great stuff, by making my own blog system by my self.

    Thanks everybody for sharing and helping, have a wonderful weekend! :-)

  • Jason Prothero 422 posts 1243 karma points c-trib
    Feb 09, 2012 @ 17:35
    Jason Prothero
    0

    FYI, I also found this example and explanation useful as a supplement on this topic:

     

    http://stackoverflow.com/questions/3442089/xsl-merge-elements-and-sort-by-date

     

     

Please Sign in or register to post replies

Write your reply to:

Draft