Copied to clipboard

Flag this post as spam?

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


  • Lee 1130 posts 3088 karma points
    Mar 10, 2011 @ 19:53
    Lee
    0

    XPath Query Help

    Ok so I have the following structure

    Forum
     - ForumCategory
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost
    - ForumCategory
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost
       - ForumTopic
           - ForumPost
           - ForumPost
           - ForumPost

    When I list out the categories I want to find the latest post in that category, so I need to find it by createDate.. i.e...

    Category Name Latest Post '18/02/78'
    Category Name Latest Post '18/02/78'
    Category Name Latest Post '18/02/78'

    When looping through I have each Category nodeID available to me only, currentPage is not as its a standalone macro which people can add anywhere.

    Any help greatly appreciated...

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Mar 10, 2011 @ 21:02
    Chriztian Steinmeier
    2

    Hi Lee,

    These templates should do it - I'm a little baffled about not having $currentPage, but maybe you can shed some light on the context you're doing this in...

    <xsl:template match="ForumCategory">
        <h2><xsl:value-of select="@nodeName" /></h2>
        <xsl:for-each select="ForumTopic/ForumPost">
            <xsl:sort select="@createDate" data-type="text" order="descending" />
    
            <!-- Only handle latest (top) item  -->
            <xsl:if test="position() = 1">
                <p>
                    <xsl:text>Latest post: </xsl:text>
                    <xsl:apply-templates select="@createDate" mode="date" />
                </p>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    
    <xsl:template match="* | @*" mode="date">
        <!-- Use FormatDateTime() here to suit your needs... -->
        <xsl:value-of select="substring(., 1, 10)" />
    </xsl:template>
    
    Since you only have the nodeID of the Category - to execute, you should be able do something like this:
    <xsl:apply-templates select="umbraco.library:GetXmlNodeById($categoryID)" />

    /Chriztian

  • Lee 1130 posts 3088 karma points
    Mar 11, 2011 @ 07:30
    Lee
    0

    Hey Chriztian

    Thanks for coming back, my bad... I didn't explain properly... I am actually going to use this in a .NET usercontrol, and I am going to use Hendys helper class which has a method in it called GetNodesFromXpath()

    Because of this I don't have XSLT available to me, just an XPath statement which will return me a set of Node object(s).   the reason currentPage won't help is because this marco which loops through the main forum categories could be put anywhere on the site and at any level, so currentPage won't help will it?  Although looking at the below I notice currentPage is used in the method

    Here is the GetNodesFromXpath() method which I need to pass the XPath query into

            public static List<Node> GetNodesFromXpath(string xPath)
            {
                var nodes = new List<Node>();
    
                if (IsCurrentNodeAvailable())
                {
                    xPath = xPath.Replace("$currentPage", "descendant::node[@id='" + Node.GetCurrent().Id + "']");
                }
    
                var xPathNavigator = umbraco.content.Instance.XmlContent.CreateNavigator(); //get all umbraco xml
                var xPathNodeIterator = xPathNavigator.Select(xPath); //TODO: check xpath string is valid
    
                Node node;
                while (xPathNodeIterator.MoveNext())
                {
                    node = GetNode(xPathNodeIterator.Current.Evaluate("string(@id)").ToString());
                    if (node != null) { nodes.Add(node); }
                }
    
                return nodes;
            }
  • kows 81 posts 151 karma points c-trib
    Mar 11, 2011 @ 09:20
    kows
    0

    and the reason you need a .NET usercontrol?

    Chriztian's solution seems valid to me (and can be put everywhere aswell).

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Mar 11, 2011 @ 10:04
    Douglas Robar
    2

    It will take more than a single xpath to do everything you want so I think you've got a non-starter here, Lee.

    But, for what it's worth, you might be able to make some assumptions about where the forum is located and save a variable for the top forum node (so you don't have to do the inefficient work of descendant-or-self more than once):

    <!-- If it will be at the top of the content tree as its own site -->
    <xsl:variable name="forumHome" select="$currentPage/ancestor-or-self::root/Forum" />
    <!-- if it will be directly below the homepage of the site currently being viewed -->
    <xsl:variable name="forumHome" select="$currentPage/ancestor-or-self::*[@level = 1]/Forum" />
    <!-- if it will be within the site the website visitor is currently viewing (can be very slow on big sites) -->
    <xsl:variable name="forumHome" select="$currentPage/ancestor-or-self::*[@level = 1]/descendant-or-self::Forum" />
    <!-- if it can be anywhere (can be extremely slow on big sites) -->
    <xsl:variable name="forumHome" select="$currentPage/ancesotor-or-self::root/descendant-or-self::Forum" />

     

    But probably better would be to have a macro parameter with a ContentPicker that asks the user to select the Forum's home page. Then you know the id and don't have to do any slow searching/guessing to find it.

     

    You can, of course, use .net to do this work but since it is all xpath based anyway I don't see an advantage - more a matter of preference. The big point is simply that this isn't a one-liner no matter the language.

    cheers,
    doug.

     

  • Lee 1130 posts 3088 karma points
    Mar 11, 2011 @ 10:18
    Lee
    0

    The reason I need to do this in .NET is because its in a partial class..

    @Doug - I have the Root forum Node Id available to me which I can pass into the query if needed?  Would that help create an efficient XPath query? I am trying to use this instead of Linq2umbraco as its very slow, so trying to use a mix of the good and bad to increase performance on big sites.

     

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Mar 11, 2011 @ 10:21
    Douglas Robar
    0

    Ah, if you've got the forumHome then you can create an xpathnodeiterator and do the logic Chriztian notes in .net. Performance ought to be okay.

    cheers,
    doug.

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Mar 11, 2011 @ 10:27
    Douglas Robar
    0

    Of course I say that not having done this myself. For memory savings, only get the forum nodes for your xPathNavigator. 

    Let us know what you come up with and how the performance goes.

    cheers,
    doug.

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Mar 11, 2011 @ 10:55
    Chriztian Steinmeier
    1

    Thought: Since the problem involves 2 steps (sorting by date descending and then picking the top-most) the first of which you can't do in XPath, maybe you could create an extension max() function - the dates are sortable strings so should probably be doable without the overhead of casting to Dates etc.

    That way you could say something like this:

    latestPostDate = Lee.Mess:Max(ForumTopic/ForumPost/@createDate);
    latestPost = XPathSelect("ForumTopic/ForumPost[@createDate = '" + latestPost + "']");

    But then again, I wouldn't trust my .NET skills that much :-)

    /Chriztian

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Mar 11, 2011 @ 11:04
    Douglas Robar
    0

    Lee.Mess

    That works on sooooo many levels! :D

     

  • Lee 1130 posts 3088 karma points
    Mar 11, 2011 @ 13:23
    Lee
    0

    Thanks everyone for posting about this... I have decided to go about it a different way at the moment but may revert back to this.  Its a bit of a cheat, but I am trying to make sure everything will work with a 100K+ node site with good performance.

Please Sign in or register to post replies

Write your reply to:

Draft