LINQ to XML: using let, yield return and SelectMany


Introduction

This blog post continues my series on LINQ. The preceding editions which cover some of my experiences with LINQ are list blow, or to the right.

This addition to the LINQ series probably qualifies in the “cruel and unusual” things which can be done with LINQ category. The techniques which are listed here are probably uses of LINQ which fall into the “corner cases” or “edge cases” of LINQ usage.

What is in the C# Source Code Below

There are a couple of things which this code shows:

  • The use of the LINQ let clause. This has proved to be a very convenient way of taking the “bulk” out of the LINQ to XML expressions, and is something which could be seen as an application of the “DRY principle”. I’ve always had the feeling that LINQ to XML was very good for creating XML documents, but was a bit on the verbose side when it came to interrogating XML. Judicious use of the let clause seems like a way to knock some of the verbosity out of the LINQ to XML.
  • There is another benefit of the judicious use of the let clause, and that is that you can imbed complex LINQ expression into LINQ statements in a convenient way. The following code segment shows let used for simple, and one complex (the InfoLines) expressions. The InfoLines is string concatenation from multiple lines.
    var question3 = (from Nodes in XDocument.Load(nodeFileName).Elements("InformationGraph").Elements("Node")
                     from ToElements in Nodes.Elements("Tos").Elements("Entity")
                     from FromElements in Nodes.Elements("Froms").Elements("Entity")
                     let InfoLines = (from InfoLines in Nodes.Elements("InformationContent").Elements("InformationConentLine")
                                      select InfoLines.Value)
                                      .DefaultIfEmpty("No information Content Recorded")
                                      .Aggregate((current, next) => current + ", " + next)
                     let ToElement = ToElements.Element("EntityName").Value
                     let ToObjType = ToElements.Element("EntityObjectType").Value
                     let ToSubSystem = ToElements.Element("SubSystem").Value
                     let FromElement = FromElements.Element("EntityName").Value
                     let FromObjType = FromElements.Element("EntityObjectType").Value
                     let FromSubSystem = FromElements.Element("SubSystem").Value
                     select MakeElements(FromElement, FromSubSystem, FromObjType, ToElement, ToSubSystem, ToObjType, InfoLines))
                    .SelectMany(A => A);
  • The above code sample also introduces another  interesting use of LINQ. This one is the MakeElements function (the code for which follows). This function demonstrates how to produce more than one output (XElement in this case) from a single input. The .SelectMany unwraps the sequence which the MakeElements function generates, into a single level sequence.
    private static IEnumerable<XElement> MakeElements(string FromEntity, string FromSubSystem, string FromObjType,
                                                      string ToEntity, string ToSubSystem, string ToObjectType,
                                                      string LinkTypeDescription)
    {
        string TargetQ = MakeNodeID(ToEntity);
        string SourceQ = MakeNodeID(FromEntity);
        string SourceSubSysQ = String.Empty;
        string TargetSybSysQ = String.Empty;
        yield return new XElement("Node",
            new XAttribute("ID", SourceQ),
            new XAttribute("Label", FromEntity),
            new XAttribute("Category", FromObjType));
        yield return new XElement("Node",
            new XAttribute("ID", TargetQ),
            new XAttribute("Label", ToEntity),
            new XAttribute("Category", ToObjectType));
    
        if (!String.IsNullOrEmpty(FromSubSystem))
        {
            SourceSubSysQ = MakeNodeID(FromEntity + "::" + FromSubSystem);
            yield return new XElement("Node",
                new XAttribute("ID", SourceSubSysQ),
                new XAttribute("Label", FromSubSystem),
                new XAttribute("Category", "SubSystem"));
            yield return new XElement("Link",
                new XAttribute("Source", SourceQ),
                new XAttribute("Target", SourceSubSysQ),
                new XAttribute("Label", "Sub System"));
            SourceQ = SourceSubSysQ;
        }
        if (!String.IsNullOrEmpty(ToSubSystem))
        {
            TargetSybSysQ = MakeNodeID(ToEntity + "::" + ToSubSystem);
            yield return new XElement("Node",
                new XAttribute("ID", TargetSybSysQ),
                new XAttribute("Label", ToSubSystem),
                new XAttribute("Category", "Subsystem"));
            yield return new XElement("Link",
                new XAttribute("Source", TargetQ),
                new XAttribute("Tagert", TargetSybSysQ),
                new XAttribute("Label", "Sub System"));
            TargetQ = TargetSybSysQ;
        }
        yield return new XElement("Link",
            new XAttribute("Source", SourceQ),
            new XAttribute("Target", TargetQ),
            new XAttribute("Label", LinkTypeDescription));
    }
    • The above function demonstrates another interesting “abuse” of the yield return statement. In this case, using the yield return to emit an XElement into the output sequence. This a approach seems to work very well. Also, please note: that the DGML elements which are being generated need to have the DGML namespace added to the XName (http://schemas.microsoft.com/vs/2009/dgml ) (that one came to light today as I was using the output from this function).
    • The following code segment is the MakeNodeID function. This is yet another demonstration of the powers of LINQ to do manipulations on a string object.
      private static String MakeNodeID(string NameString)
      {
          return new String(NameString.Where(A => !Char.IsPunctuation(A) && !Char.IsSeparator(A)).ToArray());
      }

    Conclusions

  • This above code samples are just fragments from the systems I’m building which generates DGML from an XML file. The XML contains information about the relationships between systems, internal and external entities in the organisation I work for. This approach seems to be panning out quite well. I’ll include some more of the “interesting” code from this development in subsequent blog posts. I have an interesting set of LINQ statements which pulls a big DGML graph apart into smaller graphs.

    Advertisements

    , , , , , , , , , ,

    1. LINQ over FileInfo And Using Let for Clarity « Craig's Eclectic Blog

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

    %d bloggers like this: