Copied to clipboard

Flag this post as spam?

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


  • John C Scott 473 posts 1183 karma points
    Feb 06, 2013 @ 07:39
    John C Scott
    0

    linq to get unique A-Z list

    I was trying to make an XSLT extension that can use linq to build an A-Z list page.

    I added a document property called "navAZ" 

    As far as I got so far was:

    IEnumerable<Node> azNodes = uQuery.GetRootNode().GetDescendantOrSelfNodes().Where(w => w.GetProperty("navAZ").Value != "");
    Dictionary<string,int> azTitles = azNodes.ToDictionary(o => o.GetProperty<string>("navAZ"),o => o.Id);
    Which isn't very far.
    The idea is that if the node has this property and it's populated with something then it would appear in the A-Z list. I thought I could use a .distinct() to get the first letter of the property and then list each node that starts with that initial.
    From the XSLT extension I wanted to return an XML navigator that looked something like
    <AtoZ>
    <initial letter="A"><node name="Ade" id="1234"/><node name="Andy" id="1244"/></initial>
    <initial letter="B"><node name="Billy" id="1254"/></initial>
    <initial letter="D"><node name="Dave" id="1268"/><node name="Dell" id="1322"/></initial>
    </AtoZ>

    where the initial element was only there if there were matches for the documents.

    I can do the last bit to generate the XML but I am really not sure what the best approach to getting the unique initial letters is and then joining that to the list of nodes (the name attribute is really very optional above and onlu really to illustrate what is going on, though I can see it could be nice).

     

     

  • John C Scott 473 posts 1183 karma points
    Feb 07, 2013 @ 19:16
    John C Scott
    0

    Well this is where I got to:

     

    namespace bucksCC.extensions.XSLTExtension
    {
        [XsltExtension(Namespace = "sa.umb.atoz")]
        public class AtoZ
        {
            public static string initials()
            {
                IEnumerable<nodeAZ> azNodes = uQuery.GetRootNode().GetDescendantOrSelfNodes()
                    .Where(w => w.GetProperty<string>("navAZ") != "")
                    .Select( n => new nodeAZ(n.Id.ToString(),n.GetProperty<string>("navAZ")));
                IEnumerable<char> initials = azNodes
                    .Select(c => c.Initial).Distinct().OrderBy(c => c);
                var joined = initials
                    .GroupJoin(azNodes, i => i, n => n.Initial, (i, n) => new { letters = i, nodes = n });
                 XDocument xdoc = new XDocument(new XElement("AtoZ",
                      from l in joined
                      select new XElement("Initial", 
                          new XAttribute("letter", l.letters),
                          new XElement("Nodes",
                              from Elements in l.nodes
                              select new XElement("Node",
                                  new XAttribute("ID", Elements.ID),
                                  new XAttribute("Name", Elements.Name)
                              )                      )                  )));
                 return xdoc.ToString();
            }
         }
    public class nodeAZ {       
    public string ID { get; set; }
    public string Name { get; set; }
            public char Initial { get; set; }
    public nodeAZ(string id, string name)
    {
                ID = id;
                Name = name;
                Initial = name[0];
            }
        }
    }

     

    ...will change return type to node iterator and not return just the xml string and also make the paramater passed in the doctype property rather than hard coding this

    I really can't tell if this is the rantings of a mad man or really ok - i'd appreciate any criticism :)

    things that would be nice to know would be
    how to do the last bit as lambda if that makes any sense
    and also how not to have the nodes wrapping the node elements 

    and generally how maybe this could be clearer and simpler

    the xml i get out looks like this

    <AtoZ>
      <Initial letter="A">
        <Nodes>
            <Node ID="1063" Name="Article"/>
        </Nodes>
      </Initial>
      <Initial letter="E">
          <Nodes>
            <Node ID="1058" Name="Event"/>
          </Nodes>
        </Initial>
        <Initial letter="N">
          <Nodes>
            <Node ID="1057" Name="Navigation"/>
            <Node ID="1064" Name="Navigation Two"/>
          </Nodes>
        </Initial>
    </AtoZ>
    any thoughts very much appreciated

     

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Feb 08, 2013 @ 17:48
    Lee Kelleher
    0

    Hi John,

    Take a look at the Enumerable.GroupBy() method.  You could do something like this:

    // get the nodes
    var nodes = uQuery.GetNodesByXPath("//*[@isDoc]");
    
    // group the nodes by first letter
    var grouping = nodes.GroupBy<umbraco.NodeFactory.Node, char>(x => char.ToUpper(x.Name[0]));
    
    // loop the grouping
    foreach (var item in grouping)
    {
        // item.Key - contains the letter
        foreach (var node in item)
        {
            // node.Name
        }
    }

    Cheers, Lee.

Please Sign in or register to post replies

Write your reply to:

Draft