<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>ViNull, Off the Record : LINQ</title><link>http://devlicio.us/blogs/vinull/archive/tags/LINQ/default.aspx</link><description>Tags: LINQ</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Using LINQ to generate HTML</title><link>http://devlicio.us/blogs/vinull/archive/2008/08/03/using-linq-to-generate-html.aspx</link><pubDate>Sun, 03 Aug 2008 17:55:20 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:41644</guid><dc:creator>Michael C. Neel</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/vinull/rsscomments.aspx?PostID=41644</wfw:commentRss><comments>http://devlicio.us/blogs/vinull/archive/2008/08/03/using-linq-to-generate-html.aspx#comments</comments><description>&lt;p&gt;&lt;a title="Balancing on the Invisible by Drew Brayshaw" href="http://flickr.com/photos/druclimb/325661568/"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;margin:0px 10px 10px 0px;border-right-width:0px;" height="244" alt="image" src="http://devlicio.us/blogs/vinull/WindowsLiveWriter/UsingLINQtogenerateHTML_B00E/image_3.png" width="165" align="left" border="0" /&gt;&lt;/a&gt; I hate seeing code mixed with markup.&lt;/p&gt;  &lt;p&gt;Seeing a template page with &lt;code&gt;&amp;lt;% if(show) { %&amp;gt;&lt;/code&gt; makes me want to claw my eyes out.&amp;#160; Seeing &lt;code&gt;String htmlTitle = &amp;quot;&amp;lt;h1&amp;gt;&amp;quot; + title + &amp;quot;&amp;lt;/h1&amp;gt;&amp;quot;&lt;/code&gt; causes me to vomit up a little something in my throat.&lt;/p&gt;  &lt;p&gt;Mixing code with markup is not a magic chocolate and peanut butter combination - it&amp;#39;s a volatile cocktail of vinegar and baking soda waiting to explode your application to tiny Server 500 Error giblets.&lt;/p&gt;  &lt;p&gt;The time comes however when we find ourselves needing to generate some well formed HTML in code, and I found myself in just such a position last night adding the agenda to the &lt;a href="http://CodeStock.org"&gt;CodeStock&lt;/a&gt; website. (Less than one week away now!)&lt;/p&gt;  &lt;p&gt;Background: On the CodeStock site, the speakers and sessions list lives in an XML file.&amp;#160; The agenda page has a grid of session times and my task was to fill in each session &amp;quot;cell&amp;quot; with the session planned for that room and time.&amp;#160; I wanted to link to the full session and also list the speaker&amp;#39;s name in the cell.&amp;#160; In the XML I have created Key elements that are used as HTML anchors in a link to a session.&amp;#160; It&amp;#39;s all very low tech, simplistic goodness.&amp;#160; An example of the XML for a speaker:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Speaker&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Brownell&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Name&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Steve Brownell&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Name&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Website&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;http://enthusiasticprogramming.blogspot.com&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Website&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Photo&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;~/Speakers/SteveBrownell.png&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Photo&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Bio&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &lt;/span&gt;Steve is the manager for research and development at AllMeds in Oak Ridge, TN.  Steve
        has been programming one thing or another for over twenty years.  AllMeds makes and
        sells a commercial software product which is an electronic medical record system.  We&amp;#39;ve
        been .NET based since 2000.  AllMeds is a VB.NET shop at heart, but the AllMeds system spans
        many areas of Windows development.
    &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Bio&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Session&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Hobbled&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Title&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
            &lt;/span&gt;The Hobbled:  There And Back Again, or Code Automation:  how I made it from the
            presentation layer to the database and back.
        &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Title&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Abstract&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
            &lt;/span&gt;Stop writing code, and start writing code that writes code.  There&amp;#39;s never been more
            choices to help you automate the creation of the data object layers immediately above
            the database.  Writing class factories and data access classes is boring, time consuming
            and wastes valuable time with expensive developer resources.  This course will examine
            two current approaches:  using a template engine and programming with the CODEDOM.  We&amp;#39;ll
            also briefly discuss other ORM techniques like LINQ to SQL Classes.
        &lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Abstract&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Level&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;200&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Level&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Technology&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;VB.NET, C#, LINQ, SQL&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Technology&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Session&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Speaker&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;(Steve was our CodeStock Speaker Idol winner, and I enjoyed seeing System.Codedom in action; something I&amp;#39;ll be playing with and posting on in the future thanks to Steve!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;LINQ to XML, and the new &amp;quot;X&amp;quot; classes that come with it make working with XML as easy as it should have always been.&amp;#160; Armed with LINQ, I decided that putting &amp;lt;%= SessionInfo(&amp;quot;Hobbled&amp;quot;) %&amp;gt; was something I could live with (had this been a larger site that needed to live longer than August 9th, I would have opted for a user control &amp;lt;CodeStock:SessionInfo Key=&amp;quot;Hobbled&amp;quot;/&amp;gt;).&amp;#160; My first LINQ expression looked something like the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;var &lt;/span&gt;info = (&lt;span style="color:blue;"&gt;from &lt;/span&gt;s &lt;span style="color:blue;"&gt;in &lt;/span&gt;speakers.Descendants(&lt;span style="color:#a31515;"&gt;&amp;quot;Session&amp;quot;&lt;/span&gt;)
            &lt;span style="color:blue;"&gt;where &lt;/span&gt;s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value.Equals(SessionKey)
            &lt;span style="color:blue;"&gt;select new &lt;/span&gt;{
                key = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value,
                title = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;).Value.Trim(),
                speaker = s.Parent.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;).Value
            }).First();&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This yields a very useful info object with just the information I need.&amp;#160; *If* I was in a hurry, and didn&amp;#39;t mind a little vomit, I would follow on with the following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;String &lt;/span&gt;hmtl = &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.Format(&lt;span style="color:#a31515;"&gt;&amp;quot;&amp;lt;a href=&amp;#39;{0:s}&amp;#39; title=&amp;#39;{1:s}&amp;#39;&amp;gt;{2:s}&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;{3:s}&amp;quot;&lt;/span&gt;,
    &lt;span style="color:blue;"&gt;new object&lt;/span&gt;[] { ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, info.key),
                   info.title,
                   info.title.Length &amp;gt; 30 ? info.title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: info.title,
                   info.speaker });&lt;/pre&gt;

&lt;p&gt;Why do I despise this so much?&amp;#160; It&amp;#39;s not easy to read, and it can become cumbersome to change.&amp;#160; ASP.NET has a collection of server controls just for generating HTML, intended for use in user controls but they are not limited to user controls alone.&amp;#160; To generate the html above would look something like this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;HtmlAnchor &lt;/span&gt;aHref = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlAnchor&lt;/span&gt;() {
    HRef = ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, info.key),
    InnerText = info.title.Length &amp;gt; 30 ? info.title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: info.title,
    Title = Title
};
&lt;span style="color:#2b91af;"&gt;HtmlGenericControl &lt;/span&gt;div = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlGenericControl&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;) {
    InnerText = info.speaker
};

&lt;span style="color:#2b91af;"&gt;StringBuilder &lt;/span&gt;html = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringBuilder&lt;/span&gt;();
&lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;StringWriter &lt;/span&gt;sw = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StringWriter&lt;/span&gt;(html)) {
    &lt;span style="color:blue;"&gt;using &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;HtmlTextWriter &lt;/span&gt;hw = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;HtmlTextWriter&lt;/span&gt;(sw)) {
        aHref.RenderControl(hw);
        div.RenderControl(hw);
        hw.Close();
    }
    sw.Close();
}&lt;/pre&gt;

&lt;p&gt;There are times when working with parts of the .Net framework I have wonder if some Java types didn&amp;#39;t design the class.&amp;#160; The mess here to render the HTML is one of those times.&amp;#160; The lack of a RenderControl that returns a String is the problem - thankfully we now have extension methods to fix the framework, but that&amp;#39;s another post.&amp;#160; No matter how much I hate markup in the code, I cannot endorse this version over the vomit inducing first solution.&lt;/p&gt;

&lt;p&gt;It occurs to me that HTML is (or was once) fundamentally XML, and I can return XML from my LINQ expression.&amp;#160; In fact, this is what LINQ is about - not just getting the data you want, but getting it in the format you need.&amp;#160; Here is the new LINQ query:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:#2b91af;"&gt;XElement &lt;/span&gt;info = (&lt;span style="color:blue;"&gt;from &lt;/span&gt;s &lt;span style="color:blue;"&gt;in &lt;/span&gt;speakers.Descendants(&lt;span style="color:#a31515;"&gt;&amp;quot;Session&amp;quot;&lt;/span&gt;)
                 &lt;span style="color:blue;"&gt;where &lt;/span&gt;s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value.Equals(SessionKey)
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;key = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Key&amp;quot;&lt;/span&gt;).Value
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;title = s.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;).Value.Trim()
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;shortTitle = title.Length &amp;gt; 30 ? 
                    title.Substring(0, 27) + &lt;span style="color:#a31515;"&gt;&amp;quot;...&amp;quot; &lt;/span&gt;: title
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;session = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;,
                              &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XAttribute&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;,
                                  ExpandURL(&lt;span style="color:#a31515;"&gt;&amp;quot;~/Pages/Agenda.aspx&amp;quot;&lt;/span&gt;, key)),
                              &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XAttribute&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;, title),
                              shortTitle)
                 &lt;span style="color:blue;"&gt;let &lt;/span&gt;speaker = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;div&amp;quot;&lt;/span&gt;, s.Parent.Element(&lt;span style="color:#a31515;"&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;).Value)
                 &lt;span style="color:blue;"&gt;select new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;XElement&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;&amp;quot;span&amp;quot;&lt;/span&gt;, session, speaker)).First();&lt;/pre&gt;

&lt;p&gt;This may not seem to some as better.&amp;#160; I myself have trouble looking at most LINQ expressions, but as I&amp;#39;m learning to &lt;a href="http://www.thinqlinq.com/"&gt;Thinq Linq&lt;/a&gt; I&amp;#39;m seeing that writing the LINQ expression is where the power lies, not in the syntax.&amp;#160; The mental dialog goes something like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;quot;Okay, from my list of speakers I want a session where the session&amp;#39;s key matches SessionKey.&amp;#160; Now, let me grab some fields I need, first the key, then the title which I need to trim off excess whitespace, then let&amp;#39;s make a short version of that title since Steve&amp;#39;s title is so long - love that title though.&amp;#160; I&amp;#39;ll need an link tag for the session; set the href and title attributes, and then add the speaker&amp;#39;s name in a div tag so I get a cheap line break.&amp;#160; I&amp;#39;m really in XML not HTML, so I&amp;#39;ll need a root node and a span tag will work without affecting layout, and I&amp;#39;ll add the link and div tags as children.&amp;quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Writing LINQ like this I feel much closer to the problem I&amp;#39;m trying to solve, and not bogged down by syntax.&amp;#160; There is still some moments I&amp;#39;m thrust back to code, such as the use of First() to select only one result.&amp;#160; I&amp;#39;d like to have a &amp;quot;select first&amp;quot; option in LINQ expressions instead of just the extension methods.&amp;#160; &lt;/p&gt;

&lt;p&gt;Is this something I&amp;#39;ll be using now every time I have this problem?&amp;#160; Not sure yet, but it&amp;#39;s another &amp;quot;tool in the box&amp;quot; I&amp;#39;ll keep around and use when it feels right.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=41644" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/vinull/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://devlicio.us/blogs/vinull/archive/tags/LINQ/default.aspx">LINQ</category></item></channel></rss>