<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:webfeeds="http://webfeeds.org/rss/1.0" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0"><channel><webfeeds:logo>http://nimblecoder.com/images/zenicon.jpg</webfeeds:logo><webfeeds:analytics id="UA" engine="GoogleAnalytics" /><title>Nimble Coder</title><link>http://nimblecoder.com/</link><description>This blog is powered by DasBlog Core built on the awesome legacy of the original DasBlog!</description><image><url>http://nimblecoder.com/images/zenicon.jpg</url><title>Nimble Coder</title><link>http://nimblecoder.com/</link></image><copyright>Ryan Van Slooten</copyright><lastBuildDate>Mon, 10 Jul 2023 19:44:25 GMT</lastBuildDate><managingEditor>ryanvs@yahoo.com</managingEditor><webMaster>ryanvs@yahoo.com</webMaster><item><trackback:ping>http://nimblecoder.com/feed/trackback/d580bf07-b62e-4ad6-b4c9-def9112515d3</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/d580bf07-b62e-4ad6-b4c9-def9112515d3</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/sql-server-converts-empty-string-to-int-0/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/d580bf07-b62e-4ad6-b4c9-def9112515d3</wfw:commentRss><title>SQL Server Converts Empty String to int 0</title><guid isPermaLink="false">http://nimblecoder.com/post/d580bf07-b62e-4ad6-b4c9-def9112515d3</guid><link>http://nimblecoder.com/sql-server-converts-empty-string-to-int-0</link><pubDate>Mon, 10 Jul 2023 19:44:25 GMT</pubDate><description>&lt;div&gt;&lt;p&gt; &lt;a href="https://sslwsh001.securedata.net/nimblecoder.com/content/binary/Open-Live-Writer/1188805e8fa1_BF8C/zero_2.png"&gt;&lt;img width="244" height="244" title="zero" align="right" style="float: right; display: inline; background-image: none;" alt="Zero or NULL?" src="https://sslwsh001.securedata.net/nimblecoder.com/content/binary/Open-Live-Writer/1188805e8fa1_BF8C/zero_thumb.png" border="0" /&gt;&lt;/a&gt;It might surprise people, but SQL Server CAST/TRY_CAST and CONVERT/TRY_CONVERT will change an empty string (‘’ or N’’) to a default value instead of NULL. This happens for numeric data types such as int, bigint, smallint, tinyint, numeric, float, bit, datetime, smalldatetime, datetime2, datetimeoffset. Also note that some data types will throw an exception on empty string such as decimal, numeric, and uniqueidentifier.&lt;/p&gt; &lt;p&gt;If you want to return NULL instead of 0, then use NULLIF first, e.g. CONVERT(int, NULLIF(@variable, ‘’))&lt;/p&gt; &lt;pre class="code enlighter sql" data-enlighter-language="sql"&gt;DECLARE @a nvarchar = ''

-- ==== Example 1A: int (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'int', title = 'CONVERT'           , value =     CONVERT(int, @a)
UNION SELECT data_type = 'int', title = 'TRY_CONVERT'       , value = TRY_CONVERT(int, @a)
UNION SELECT data_type = 'int', title = 'CAST'              , value =     CAST(@a AS int)
UNION SELECT data_type = 'int', title = 'TRY_CAST'          , value = TRY_CAST(@a AS int)
-- Returns
-- data_type | title       | value
-- --------- | ----------- | -----
-- int       | CAST        | 0
-- int       | CONVERT     | 0
-- int       | TRY_CAST    | 0
-- int       | TRY_CONVERT | 0

-- ==== Example 1B: int (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'int', title = 'CONVERT+NULLIF'    , value =     CONVERT(int, NULLIF(@a, ''))
UNION SELECT data_type = 'int', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(int, NULLIF(@a, ''))
UNION SELECT data_type = 'int', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS int)
UNION SELECT data_type = 'int', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS int)
-- Returns
-- data_type | title              | value
-- --------- | ------------------ | -----
-- int       | CAST+NULLIF        | NULL
-- int       | CONVERT+NULLIF     | NULL
-- int       | TRY_CAST+NULLIF    | NULL
-- int       | TRY_CONVERT+NULLIF | NULL


-- ==== Example 2A: datetime (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'datetime', title = 'CONVERT'           , value =     CONVERT(datetime, @a)
UNION SELECT data_type = 'datetime', title = 'TRY_CONVERT'       , value = TRY_CONVERT(datetime, @a)
UNION SELECT data_type = 'datetime', title = 'CAST'              , value =     CAST(@a AS datetime)
UNION SELECT data_type = 'datetime', title = 'TRY_CAST'          , value = TRY_CAST(@a AS datetime)
-- Returns
-- data_type | title       | value
-- --------- | ----------- | -----------------------
-- datetime  | CAST        | 1900-01-01 00:00:00.000
-- datetime  | CONVERT     | 1900-01-01 00:00:00.000
-- datetime  | TRY_CAST    | 1900-01-01 00:00:00.000
-- datetime  | TRY_CONVERT | 1900-01-01 00:00:00.000

-- ==== Example 2B: datetime (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'datetime', title = 'CONVERT+NULLIF'    , value =     CONVERT(datetime, NULLIF(@a, ''))
UNION SELECT data_type = 'datetime', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(datetime, NULLIF(@a, ''))
UNION SELECT data_type = 'datetime', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS datetime)
UNION SELECT data_type = 'datetime', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS datetime)
-- Returns
-- data_type | title              | value
-- --------- | ------------------ | -----
-- datetime  | CAST+NULLIF        | NULL
-- datetime  | CONVERT+NULLIF     | NULL
-- datetime  | TRY_CAST+NULLIF    | NULL
-- datetime  | TRY_CONVERT+NULLIF | NULL


-- ==== Example 3A: float (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'float', title = 'CONVERT'           , value =     CONVERT(float, @a)
UNION SELECT data_type = 'float', title = 'TRY_CONVERT'       , value = TRY_CONVERT(float, @a)
UNION SELECT data_type = 'float', title = 'CAST'              , value =     CAST(@a AS float)
UNION SELECT data_type = 'float', title = 'TRY_CAST'          , value = TRY_CAST(@a AS float)
-- Returns
-- data_type | title       | value
-- --------- | ----------- | -----
-- float     | CAST        | 0
-- float     | CONVERT     | 0
-- float     | TRY_CAST    | 0
-- float     | TRY_CONVERT | 0

-- ==== Example 3B: float (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'float', title = 'CONVERT+NULLIF'    , value =     CONVERT(float, NULLIF(@a, ''))
UNION SELECT data_type = 'float', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(float, NULLIF(@a, ''))
UNION SELECT data_type = 'float', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS float)
UNION SELECT data_type = 'float', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS float)
-- Returns
-- data_type | title              | value
-- --------- | ------------------ | -----
-- float     | CAST+NULLIF        | NULL
-- float     | CONVERT+NULLIF     | NULL
-- float     | TRY_CAST+NULLIF    | NULL
-- float     | TRY_CONVERT+NULLIF | NULL


-- ==== Example 4A: decimal (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'decimal', title = 'CONVERT'           , value =     CONVERT(decimal, @a)
UNION SELECT data_type = 'decimal', title = 'TRY_CONVERT'       , value = TRY_CONVERT(decimal, @a)
UNION SELECT data_type = 'decimal', title = 'CAST'              , value =     CAST(@a AS decimal)
UNION SELECT data_type = 'decimal', title = 'TRY_CAST'          , value = TRY_CAST(@a AS decimal)
-- Throws Error 8114: Error converting data type nvarchar to numeric.

-- ==== Example 4B: decimal (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'decimal', title = 'CONVERT+NULLIF'    , value =     CONVERT(decimal, NULLIF(@a, ''))
UNION SELECT data_type = 'decimal', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(decimal, NULLIF(@a, ''))
UNION SELECT data_type = 'decimal', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS decimal)
UNION SELECT data_type = 'decimal', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS decimal)
-- Returns
-- data_type | title              | value
-- --------- | ------------------ | -----
-- decimal   | CAST+NULLIF        | NULL
-- decimal   | CONVERT+NULLIF     | NULL
-- decimal   | TRY_CAST+NULLIF    | NULL
-- decimal   | TRY_CONVERT+NULLIF | NULL


-- ==== Example 5A: numeric (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'numeric', title = 'CONVERT'           , value =     CONVERT(numeric, @a)
UNION SELECT data_type = 'numeric', title = 'TRY_CONVERT'       , value = TRY_CONVERT(numeric, @a)
UNION SELECT data_type = 'numeric', title = 'CAST'              , value =     CAST(@a AS numeric)
UNION SELECT data_type = 'numeric', title = 'TRY_CAST'          , value = TRY_CAST(@a AS numeric)
-- Throws Error 8114: Error converting data type nvarchar to numeric.

-- ==== Example 5B: numeric (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'numeric', title = 'CONVERT+NULLIF'    , value =     CONVERT(numeric, NULLIF(@a, ''))
UNION SELECT data_type = 'numeric', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(numeric, NULLIF(@a, ''))
UNION SELECT data_type = 'numeric', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS numeric)
UNION SELECT data_type = 'numeric', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS numeric)
-- Returns
-- data_type | title              | value
-- --------- | ------------------ | -----
-- numeric   | CAST+NULLIF        | NULL
-- numeric   | CONVERT+NULLIF     | NULL
-- numeric   | TRY_CAST+NULLIF    | NULL
-- numeric   | TRY_CONVERT+NULLIF | NULL

-- 6: data_type = uniqueidentifier

-- ==== Example 6A: uniqueidentifier (empty string) ====
-- Returns 0 instead of NULL
      SELECT data_type = 'uniqueidentifier', title = 'CONVERT'           , value =     CONVERT(uniqueidentifier, @a)
UNION SELECT data_type = 'uniqueidentifier', title = 'TRY_CONVERT'       , value = TRY_CONVERT(uniqueidentifier, @a)
UNION SELECT data_type = 'uniqueidentifier', title = 'CAST'              , value =     CAST(@a AS uniqueidentifier)
UNION SELECT data_type = 'uniqueidentifier', title = 'TRY_CAST'          , value = TRY_CAST(@a AS uniqueidentifier)
-- Throws Error 8169: Conversion failed when converting from a character string to uniqueidentifier.

-- ==== Example 6B: uniqueidentifier (NULLIF) ====
-- Returns NULL
      SELECT data_type = 'uniqueidentifier', title = 'CONVERT+NULLIF'    , value =     CONVERT(uniqueidentifier, NULLIF(@a, ''))
UNION SELECT data_type = 'uniqueidentifier', title = 'TRY_CONVERT+NULLIF', value = TRY_CONVERT(uniqueidentifier, NULLIF(@a, ''))
UNION SELECT data_type = 'uniqueidentifier', title = 'CAST+NULLIF'       , value =     CAST(NULLIF(@a, '') AS uniqueidentifier)
UNION SELECT data_type = 'uniqueidentifier', title = 'TRY_CAST+NULLIF'   , value = TRY_CAST(NULLIF(@a, '') AS uniqueidentifier)
-- Returns
-- data_type        | title              | value
-- ---------------- | ------------------ | -----
-- uniqueidentifier | CAST+NULLIF        | NULL
-- uniqueidentifier | CONVERT+NULLIF     | NULL
-- uniqueidentifier | TRY_CAST+NULLIF    | NULL
-- uniqueidentifier | TRY_CONVERT+NULLIF | NULL
&lt;/pre&gt;
&lt;pre class="code enlighter sql" data-enlighter-language="sql" style="clear:both;"&gt;-- ==== JSON ====
-- NOTE: Empty string will default to integer 0 instead of NULL
DECLARE @json nvarchar(max) = N&amp;apos;[
{&amp;quot;a&amp;quot;:0},
{&amp;quot;a&amp;quot;:1, &amp;quot;b&amp;quot;:2 },
{&amp;quot;a&amp;quot;:3, &amp;quot;b&amp;quot;:&amp;quot;&amp;quot;}
]&amp;apos;

SELECT  a
    ,   b
FROM    OPENJSON(@json)
        WITH (
            a           int
        ,   b           int
        )
-- Returns:
-- a | b
-- 0 | NULL
-- 1 | 2
-- 3 | 0

-- NOTE: Must manually convert string to integer to avoid empty string defaulting to 0
SELECT  a   = TRY_CONVERT(int, NULLIF(a, &amp;apos;&amp;apos;))
    ,   b   = TRY_CONVERT(int, NULLIF(b, &amp;apos;&amp;apos;))
FROM    OPENJSON(@json)
        WITH (
            a           varchar(30)
        ,   b           varchar(30)
        )
-- Returns:
-- a | b
-- 0 | NULL
-- 1 | 2
-- 3 | NULL


-- ==== XML ====
-- NOTE: Empty string will default to integer 0 instead of NULL
DECLARE @xml xml = N&amp;apos;&amp;lt;xml&amp;gt;
&amp;lt;row a=&amp;quot;0&amp;quot;/&amp;gt;
&amp;lt;row a=&amp;quot;1&amp;quot; b=&amp;quot;2&amp;quot;/&amp;gt;
&amp;lt;row a=&amp;quot;3&amp;quot; b=&amp;quot;&amp;quot; /&amp;gt;
&amp;lt;/xml&amp;gt;&amp;apos;

SELECT  a   = t.x.value(&amp;apos;@a&amp;apos;, &amp;apos;int&amp;apos;)
    ,   b   = t.x.value(&amp;apos;@b&amp;apos;, &amp;apos;int&amp;apos;)
FROM    @xml.nodes(&amp;apos;/xml/row&amp;apos;) AS t(x)
-- Returns:
-- a | b
-- 0 | NULL
-- 1 | 2
-- 3 | 0

-- NOTE: Must manually convert string to integer to avoid empty string defaulting to 0
SELECT  a   = TRY_CONVERT(int, NULLIF(t.x.value(&amp;apos;@a&amp;apos;, &amp;apos;varchar(30)&amp;apos;), &amp;apos;&amp;apos;))
    ,   b   = TRY_CONVERT(int, NULLIF(t.x.value(&amp;apos;@b&amp;apos;, &amp;apos;varchar(30)&amp;apos;), &amp;apos;&amp;apos;))
FROM    @xml.nodes(&amp;apos;/xml/row&amp;apos;) AS t(x)
-- Returns:
-- a | b
-- 0 | NULL
-- 1 | 2
-- 3 | NULL
&lt;/pre&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/sql-server-converts-empty-string-to-int-0/comments#comments-start</comments><category>SQL</category></item><item xml:lang="en"><trackback:ping>http://nimblecoder.com/feed/trackback/8f73dffc-7ff5-4593-aa19-5d7bc00fbb20</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/8f73dffc-7ff5-4593-aa19-5d7bc00fbb20</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/migrated-to-dasblog-core/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/8f73dffc-7ff5-4593-aa19-5d7bc00fbb20</wfw:commentRss><slash:comments>2</slash:comments><title>Migrated to dasBlog Core</title><guid isPermaLink="false">http://nimblecoder.com/post/8f73dffc-7ff5-4593-aa19-5d7bc00fbb20</guid><link>http://nimblecoder.com/migrated-to-dasblog-core</link><pubDate>Thu, 23 Mar 2023 13:15:28 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;I have migrated my blog to &lt;a href="https://github.com/poppastring/dasblog-core"&gt;dasBlog Core&lt;/a&gt;. Originally I used &lt;a href="https://github.com/Haacked/Subtext/"&gt;SubText&lt;/a&gt; and then later &lt;a href="https://github.com/madskristensen/Miniblog.Core"&gt;MiniBlog.Core&lt;/a&gt; and experimented with &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; but the exporting format wasn't what I wanted. So for the most part haven't blogged in about ten years and left it dormant. After all that time, I decided to resurrect the blog with a .NET Core based engine, although I will probably keep Jekyll with GitHub Pages as a backup mechanism.&lt;/p&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/migrated-to-dasblog-core/comments#comments-start</comments><category>General</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/c7d20c79-9cad-4b5c-a55b-5fe0cda3bd4f</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/c7d20c79-9cad-4b5c-a55b-5fe0cda3bd4f</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/do-not-hide-important-calculations-and-details/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/c7d20c79-9cad-4b5c-a55b-5fe0cda3bd4f</wfw:commentRss><title>Do Not Hide Important Calculations and Details</title><guid isPermaLink="false">http://nimblecoder.com/post/c7d20c79-9cad-4b5c-a55b-5fe0cda3bd4f</guid><link>http://nimblecoder.com/do-not-hide-important-calculations-and-details</link><pubDate>Tue, 07 Apr 2015 19:51:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;Have you ever worked on a project that involved a requirement with an IF statement with several branches and multiple conditionals in each branch? Then the programmer takes the simplest approach and programs it exactly as it was written. Later, there are issues and it becomes very difficult to debug this logic.&lt;/p&gt;  &lt;p&gt;I was working on a project recently that involved a complex calculation for the timeliness of a process order. The logic included checks to see if the process order was running (had any jobs started?), to see if any jobs started late or missing required finish times, and more comparisons. I was not responsible for the original implementation, but I was asked to investigate and fix it after the customer had issues with the calculations.&lt;/p&gt;  &lt;p&gt;The specification included requirements such as (paraphrased):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The status will be “DELAY” if any of the following conditions are true:&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;the job has not started and the scheduled start time has passed but the latest start time has not passed yet.&lt;/li&gt;      &lt;li&gt;the job is running and it started after the scheduled start time but before the latest start time.&lt;/li&gt;      &lt;li&gt;the job is completed and it finished after the scheduled finish time but before the required finish time.&lt;/li&gt;      &lt;li&gt;&amp;lt;more conditions...&amp;gt;&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;The status will be “LATE” if any of the following conditions are true:&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;the job has not started and both the scheduled and latest start times have passed.&lt;/li&gt;      &lt;li&gt;the job started after the latest start time.&lt;/li&gt;      &lt;li&gt;the job is completed and it finished after the required finish time.&lt;/li&gt;      &lt;li&gt;&amp;lt;more conditions...&amp;gt;&lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;The more complicated the logic and conditions, the more important it is to expose these details both for debugging purposes and for the user or administrator.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;There were several issues I uncovered with the above specification as well as enhancements that I added.&lt;/p&gt;  &lt;p&gt;One of the primary issues was the general status of either “DELAY” or “LATE” without indicating which condition was responsible for the status. For example, the customer noticed a process order was marked as “LATE” even though the required finish time had not elapsed. It turned out the process started late, but it was not easy to figure that out with the information provided on the screen at the time.&lt;/p&gt;  &lt;p&gt;Consequently, I enhanced the status codes to return more information. There are two basic options: change the status codes, or add a sub-status code with the detailed information.&lt;/p&gt;  &lt;p&gt;The typical implementation of conditions and logic look something like this (shown in a SQL-style language but it really does not matter which language is used):&lt;/p&gt;  &lt;p&gt;My implementation was actually in SQL since the goal was to reduce the data returned to the client application. You could implement it in the client application, but that results significantly more data transmitted and slows the client application and decreases the available bandwidth for all users.&lt;/p&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/do-not-hide-important-calculations-and-details/comments#comments-start</comments></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/bfd40708-72df-4b16-b8a2-a215cf2b05cd</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/bfd40708-72df-4b16-b8a2-a215cf2b05cd</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/formatting-xml-in-excelvb/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/bfd40708-72df-4b16-b8a2-a215cf2b05cd</wfw:commentRss><title>Formatting XML in Excel/VB</title><guid isPermaLink="false">http://nimblecoder.com/post/bfd40708-72df-4b16-b8a2-a215cf2b05cd</guid><link>http://nimblecoder.com/formatting-xml-in-excelvb</link><pubDate>Wed, 23 May 2007 20:23:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;I was working on a spreadsheet that submitted XML data to a web service and the XML that was being generated by the XmlDocument object was not very tidy. Normally with C# I use Tidy.NET to clean up the HTML or XML, but since this was being used in Excel I didn't want to have any external dependencies. I found the following code online and it seems to work pretty well:&lt;/p&gt; &lt;pre class="code enlighter vb" data-enlighter-language="vb"&gt;Option Explicit

' http://www.vb-helper.com/howto_formatted_xml_document.html
' Add formatting to the document.
Public Sub FormatXmlDocument(ByVal xml_doc As DOMDocument)
    FormatXmlNode xml_doc.documentElement, 0
End Sub

' Add formatting to this element. Indent it and add a
' carriage return before its children. Then recursively
' format the children with increased indentation.
Private Sub FormatXmlNode(ByVal node As IXMLDOMNode, _
                          ByVal indent As Integer)
Dim child As IXMLDOMNode
Dim text_only As Boolean

    ' Do nothing if this is a text node.
    If TypeOf node Is IXMLDOMText Then Exit Sub

    ' See if this node contains only text.
    text_only = True
    If node.hasChildNodes Then
        For Each child In node.childNodes
            If Not (TypeOf child Is IXMLDOMText) Then
                text_only = False
                Exit For
            End If
        Next child
    End If

    ' Process child nodes.
    If node.hasChildNodes Then
        ' Add a carriage return before the children.
        If Not text_only Then
            node.insertBefore _
                node.ownerDocument.createTextNode(vbCrLf), _
                node.FirstChild
        End If

        ' Format the children.
        For Each child In node.childNodes
            FormatXmlNode child, indent + 2
        Next child
    End If

    ' Format this element.
    If indent &amp;gt; 0 Then
        ' Indent before this element.
        node.parentNode.insertBefore _
            node.ownerDocument.createTextNode(Space$(indent)), _
            node

        ' Indent after the last child node.
        If Not text_only Then _
            node.appendChild _
                node.ownerDocument.createTextNode(Space$(indent))

        ' Add a carriage return after this node.
        If node.nextSibling Is Nothing Then
            node.parentNode.appendChild _
                node.ownerDocument.createTextNode(vbCrLf)
        Else
            node.parentNode.insertBefore _
                node.ownerDocument.createTextNode(vbCrLf), _
                node.nextSibling
        End If
    End If
End Sub&lt;/pre&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/formatting-xml-in-excelvb/comments#comments-start</comments><category>Excel</category><category>VB</category><category>XML</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/98f9edaf-d714-4426-aa9a-cc42f5f6534c</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/98f9edaf-d714-4426-aa9a-cc42f5f6534c</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/packing-it-in-there/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/98f9edaf-d714-4426-aa9a-cc42f5f6534c</wfw:commentRss><title>Packing It In There</title><guid isPermaLink="false">http://nimblecoder.com/post/98f9edaf-d714-4426-aa9a-cc42f5f6534c</guid><link>http://nimblecoder.com/packing-it-in-there</link><pubDate>Mon, 14 May 2007 21:21:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;One of the projects I worked on was an embedded turbine controller that had an incredible amount of inherent complexity designed into the product. The controller used two processors, Motorola 68360 and MPC505, as well as dual-port memory for the inter-process communications (IPC). The developers spent a substantial amount of time installing the development software and trying to get the processors to communicate. This was the era where the software would be licensed to a &lt;a href="http://en.wikipedia.org/wiki/Network_card"&gt;NIC&lt;/a&gt; and so you could only compile the code on the machine with the licensed NIC. They even hired a consultant to help figure out how to make the processors talk.&lt;/p&gt; &lt;p&gt;I caught the tail-end of this project and it was not a pleasant beginning. My responsibility was to finish the PC configuration software for the controller after the high-priced consultant left. I had just moved over from another project so I had no exposure to this project. I found an incredibly complicated database schema and object-oriented software (C++/MFC-based) to go with the overly complicated controller! The consultant apparently had never heard of the &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS principle&lt;/a&gt; (where possible) and had created a behomoth. I had to dig through many, many classes and debug all of the classes to find why the database wouldn't save correctly. I found most of the time the consultant forgot to call the parent class constructor from the derived class constructor, although there were plenty of other bugs to fix.&lt;/p&gt; &lt;p&gt;One of the developers created an emulation program for the embedded controller that ran on a PC. The configuration software worked great with the emulation program, but would not talk to the actual embedded controller. It turned out it was a combination of structure packing and &lt;a href="http://en.wikipedia.org/wiki/Endian"&gt;Endian&lt;/a&gt; problems. When the developers were trying to make the embedded processors talk, they chose a packing scheme that could not be natively duplicated by Windows or Visual Studio. The actual statement was:&lt;/p&gt; &lt;pre class="code enlighter c" data-enlighter-language="c"&gt;#pragma pack(4,8)&lt;/pre&gt;

&lt;p&gt;Unfortunately I don't have the documentation handy, but as I recall it meant&amp;nbsp;to align on 4-byte boundaries and align sub-structures on 8-byte boundaries. The key was the sub-structures and I couldn't get Visual Studio to duplicate the packing schema with the sub-structures without affecting the host structure as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"It seemed like a good idea at the time..."&lt;/em&gt; Here are the elaborate steps I took to solve the problem:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I ended up using some macros to extract the structures from the header files (there were lots and lots of structures) and put them into Excel.&lt;/li&gt;
&lt;li&gt;I created the Excel spreadsheet and scripts to automatically calculate the size of the structure on the embedded platform and to look for "Endian" data types (mainly doubles and longs).&lt;/li&gt;
&lt;li&gt;I created another Excel script to generate a C file that contained a string that contained the information to encode and decode the message. The script accounted for padding and endian conversion.&lt;/li&gt;
&lt;li&gt;The conversion function was used in the emulator and the configuration software and worked successfully.&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;In hind sight, this solution was reasonable (since we didn't want to modify the embedded controller)&amp;nbsp;but there is a very good reason you occassionally see:&lt;/p&gt;
&lt;pre class="code enlighter c" data-enlighter-language="c"&gt;WORD Reserved1;
WORD Reserved2;&lt;/pre&gt;

&lt;p&gt;throughout system header files. It is a &lt;strong&gt;very good idea&lt;/strong&gt; to add manual packing variables rather than relying on the compiler to do it for you, especially if the software will be used cross-platform.&lt;/p&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/packing-it-in-there/comments#comments-start</comments><category>General</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/64fef366-9ae0-48f3-8e26-dcf2f2baa1ff</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/64fef366-9ae0-48f3-8e26-dcf2f2baa1ff</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/json-in-c-part-1/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/64fef366-9ae0-48f3-8e26-dcf2f2baa1ff</wfw:commentRss><title>JSON in C# (Part 1)</title><guid isPermaLink="false">http://nimblecoder.com/post/64fef366-9ae0-48f3-8e26-dcf2f2baa1ff</guid><link>http://nimblecoder.com/json-in-c-part-1</link><pubDate>Sat, 12 May 2007 06:07:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;There is something simple about &lt;a href="http://www.json.org/"&gt;JSON&lt;/a&gt; -- not that it can't be complex as well -- but simple data structures (where possible) should always be the goal. I was writing a simple test application for a web service and I wanted to save a history of the parameters I tested and also be able to use a combo box and retrieve past parameters. The web service had four parameters and I wanted to use a simple Javascript or Python style dictionary.&lt;/p&gt; &lt;pre class="code enlighter js" data-enlighter-language="js"&gt;var parameter = {
    grName: "host1",
    grNode: "test",
    template: "$AnalogDevice",
    filter: "&amp;lt;filter&amp;gt;&amp;lt;Attribute name='Description' include='1' /&amp;gt;&amp;lt;/filter&amp;gt;"
};&lt;/pre&gt;

&lt;p&gt;I looked at two C# possibilities from &lt;a href="http://jayrock.berlios.de/"&gt;Jayrock&lt;/a&gt; and &lt;a href="http://www.newtonsoft.com/products/json/"&gt;Newtonsoft&lt;/a&gt;, but my web service and test application were both ASP.NET 1.1 at the time and both of these options were for .NET 2.0. So I ended up using XML by modifying &lt;a href="http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx"&gt;SerializableDictionary&lt;/a&gt; from Paul Welter&amp;nbsp;for .NET 1.1&amp;nbsp;and I used an&amp;nbsp;XmlFragmentWriter to write the parameters into the XmlDocument or to extract parameters from the document. The result is not very appealing:&lt;/p&gt;
&lt;pre class="code enlighter json" data-enlighter-language="json"&gt;&amp;lt;xml&amp;gt;
    &amp;lt;Parameters&amp;gt;
        &amp;lt;SerializableListDictionary&amp;gt;
            &amp;lt;item&amp;gt;
                &amp;lt;key&amp;gt;grNode&amp;lt;/key&amp;gt;
                &amp;lt;value&amp;gt;node&amp;lt;/value&amp;gt;
            &amp;lt;/item&amp;gt;
            &amp;lt;item&amp;gt;
                &amp;lt;key&amp;gt;grName&amp;lt;/key&amp;gt;
                &amp;lt;value&amp;gt;somename&amp;lt;/value&amp;gt;
            &amp;lt;/item&amp;gt;
            &amp;lt;item&amp;gt;
                &amp;lt;key&amp;gt;templateName&amp;lt;/key&amp;gt;
                &amp;lt;value&amp;gt;$Well.WellHead.Choke&amp;lt;/value&amp;gt;
            &amp;lt;/item&amp;gt;
            &amp;lt;item&amp;gt;
                &amp;lt;key&amp;gt;xmlFilter&amp;lt;/key&amp;gt;
                &amp;lt;value&amp;gt;
                    &amp;amp;lt;filter&amp;amp;gt;
                    &amp;amp;lt;Attribute name="Area" include="1" /&amp;amp;gt;
                    &amp;amp;lt;Attribute name="Tagname" include="1" /&amp;amp;gt;
                    &amp;amp;lt;Attribute name="Description" include="1" /&amp;amp;gt;
                    &amp;amp;lt;Attribute name="DeploymentStatus" include="1" /&amp;amp;gt;
                    &amp;amp;lt;/filter&amp;amp;gt;
                &amp;lt;/value&amp;gt;
            &amp;lt;/item&amp;gt;
        &amp;lt;/SerializableListDictionary&amp;gt;
    &amp;lt;/Parameters&amp;gt;
&amp;lt;/xml&amp;gt;&lt;/pre&gt;

&lt;p&gt;I suppose it would have been simpler to use a DataSet, but the whole point of the web service tester was to design an interface that would support multiple web methods that take different parameters that would have a different schema. I could have just written&amp;nbsp;methods to read and write the dictionary keys and values under the SelectNodes("/xml/Parameters") nodes, but there is something appealing about a serialization mechanism. As much as I detested MFC, there was something very nice about the code: &lt;span style="font-family: courier new, consolas, fixed"&gt;ar &amp;lt;&amp;lt; m_oObject;&lt;/span&gt;&amp;nbsp; Now mind you, when I was trying to figure out how to make the (typically) binary serialization mechanism in MFC use XML instead (sometime around 1999), I &lt;strong&gt;wasn't&lt;/strong&gt; pontificating on the wonders of MFC! I eventually figured out how to do that but it was a lot more challenging at the time than it needed to be!&lt;/p&gt;

&lt;p&gt;Well, unfortunately I haven't had the time to try either of the JSON components, but I will write about it when I get the time. I'm still not sure if I will mix XML and JSON or just use JSON. Since I'm trying to compare, I will probably just use JSON. After all, the point of using XML is to be able to use the myriad of XML options and if you put JSON elements in XML, you've lost the native parsing capability.&lt;/p&gt;
&lt;pre class="code enlighter xml" data-enlighter-language="xml"&gt;&amp;lt;xml&amp;gt;
    &amp;lt;Parameters&amp;gt;
        &amp;lt;!-- Missing native parsing capability by mixing xml and JSON --&amp;gt;
        &amp;lt;item&amp;gt;
            var filter = { grNode: "node", grName: "somename", templateName: "$Well.WellHead.Choke" }
        &amp;lt;/item&amp;gt;
    &amp;lt;/Parameters&amp;gt;
&amp;lt;/xml&amp;gt;&lt;/pre&gt;

&lt;p&gt;You might as well choose all XML or all JSON:&lt;/p&gt;
&lt;pre class="code enlighter json" data-enlighter-language="json"&gt;var Parameters = [
    { grNode: "node", grName: "somename", templateName: "$WellHead.Well.Choke" },
    { grNode: "node2", grName: "somename2", templateName: "$WellHead.Well.Bore" },
];&lt;/pre&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/json-in-c-part-1/comments#comments-start</comments><category>C#</category><category>JSON</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/a6f177b8-54c0-4e2b-8257-dad0ac68dea3</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/a6f177b8-54c0-4e2b-8257-dad0ac68dea3</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/vmware-server-vs-virtual-server/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/a6f177b8-54c0-4e2b-8257-dad0ac68dea3</wfw:commentRss><title>VMware Server vs. Virtual Server</title><guid isPermaLink="false">http://nimblecoder.com/post/a6f177b8-54c0-4e2b-8257-dad0ac68dea3</guid><link>http://nimblecoder.com/vmware-server-vs-virtual-server</link><pubDate>Mon, 07 May 2007 19:38:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;A while ago I switched from Virtual Server 2005 R2 to VMware Server and so far I think it was a good switch. Unfortunately it wasn't without some consequences -- mainly that I should have read the procedure prior to converting my VM image. I had the Virtual Server extensions installed on my image and I forgot to remove them and then I seemed to be unable to remove them without doing extensive damage to the image. Now I am not able to install the VMware Tools as it causes the mouse to freak out and navigating through the keyboard is increasingly challenging these days, not to mention a pain.&lt;/p&gt;  &lt;p&gt;I even went through the trouble of searching through the registry to find the Microsoft extensions and remove them. I also removed the C:\Program Files\Virtual Machine Additions folder and used &lt;a href="http://www.microsoft.com/technet/sysinternals/SystemInformation/Autoruns.mspx"&gt;Autoruns&lt;/a&gt; to remove the additions driver. The bottom line is -- don't bother -- it broke and wasn't worth fixing. Alas, I will have to put up with the annoyances (having to use Ctrl-Alt to release the cursor, finding out the system time is inaccurate after suspending the image, not being able to use the clipboard across the host and VM, etc.).&lt;/p&gt;  &lt;p&gt;Since then I created a new image from scratch (for a different purpose so I still occasionally use the older image) and it is working great. Oh well, I'll get around to recreating the old image sometime soon.&lt;/p&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/vmware-server-vs-virtual-server/comments#comments-start</comments><category>VM</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/c05bab9c-4ebc-4288-a1ca-35439fd93879</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/c05bab9c-4ebc-4288-a1ca-35439fd93879</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/subtext-blog-engine-configuration/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/c05bab9c-4ebc-4288-a1ca-35439fd93879</wfw:commentRss><title>Subtext Blog Engine Configuration</title><guid isPermaLink="false">http://nimblecoder.com/post/c05bab9c-4ebc-4288-a1ca-35439fd93879</guid><link>http://nimblecoder.com/subtext-blog-engine-configuration</link><pubDate>Thu, 03 May 2007 19:32:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;I really like &lt;a href="https://github.com/Haacked/Subtext/"&gt;Subtext&lt;/a&gt;, but unfortunately I haven't had too much time to try to configure my blog. I've looked through the wiki, but haven't seen enough information to emulate the configuration of Subtext founder &lt;a href="http://haacked.com/"&gt;Phil Haack&lt;/a&gt;. For example, the FeedBurner plugin which lists the number of subscribers and links to get the RSS and even email feeds -- how exactly is that configured? I suppose I should RTFM but I'm having trouble finding it at the moment (not to mention I have &lt;strong&gt;way too much &lt;/strong&gt;to do right now with work!). It seems the &lt;a href="http://www.subtextproject.com/Home/Wiki/tabid/150/Default.aspx"&gt;Subtext Wiki&lt;/a&gt; is describing &lt;a href="http://www.subtextproject.com/DesktopDefault.aspx?tabid=150&amp;amp;pageID=4&amp;amp;pageName="&gt;plug-in features&lt;/a&gt; in Subtext 2.0 (I'm running 1.9.x currently -- 2.0 is not released yet) so that doesn't help.&lt;/p&gt;  &lt;p&gt;Sooner or later I will install &lt;a href="http://www.php-compiler.net/doku.php"&gt;Phalanger&lt;/a&gt; and test out &lt;a href="http://wiki.splitbrain.org/wiki:dokuwiki"&gt;DokuWiki&lt;/a&gt;. I also want to install &lt;a href="http://umbraco.org/"&gt;umbraco&lt;/a&gt; and possibly &lt;a href="http://community.rainbowportal.net/"&gt;Rainbow portal&lt;/a&gt; while I'm at it. I'd love to have &lt;a href="http://www.gnu.org/software/mailman/"&gt;GNU Mailman&lt;/a&gt; installed to manage mailing lists, but there are too many issues related its dependence on UNIX-style usernames and groups and I would probably need to user &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPython&lt;/a&gt; for the &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; functionality. I guess it is just too much work right now, especially as I am utterly swamped at work. Unfortunately at work I am stuck working on a design portion of a project and I don't even get to do "real" programming that much -- sometimes you long to launch Visual Studio or work on source code. Oh well, hopefully this phase will end soon.&lt;/p&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/subtext-blog-engine-configuration/comments#comments-start</comments><category>General</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/d4fd15b7-1380-40da-8887-c98794f21778</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/d4fd15b7-1380-40da-8887-c98794f21778</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/disabling-fields-on-submit/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/d4fd15b7-1380-40da-8887-c98794f21778</wfw:commentRss><title>Disabling Fields on Submit</title><guid isPermaLink="false">http://nimblecoder.com/post/d4fd15b7-1380-40da-8887-c98794f21778</guid><link>http://nimblecoder.com/disabling-fields-on-submit</link><pubDate>Wed, 02 May 2007 08:31:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;A while back I needed to disable fields on a web page during submit and I found a utility written by Nancy Michell for &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/07/WebQA/default.aspx"&gt;MSDN Magazine&lt;/a&gt;. The utility covered the basic cases, but I found that I needed to use it for AJAX style calls as well as standard submits. So I modified the code to include an enable function as well. Finally I added exception handling around the disable and enable code to avoid pesky Javascript errors. The only thing I might change is to capture an array of the controls that were successfully disabled and then process only those controls on enable.&lt;/p&gt; &lt;p&gt;To use the disable utility, do the following:&lt;/p&gt; &lt;pre class="code enlighter csharp" data-enlighter-language="csharp"&gt;// Method 1: Using the param string[] for controls
DisableHelper.DisableCtrlOnSubmit(this,
    "ServerForm.btnCancel",
    "ServerForm.btnSave");

// Method 2: Using the ArrayList of controls
aryDisableControls = new ArrayList();
aryDisableControls.Add("ConfigLoopForm.btnCancel");
aryDisableControls.Add("ConfigLoopForm.btnSave");
DisableHelper.DisableCtrlOnSubmit(this, aryDisableControls);
&lt;/pre&gt;

&lt;p&gt;Here is the utility source:&lt;/p&gt;
&lt;pre class="code enlighter csharp" data-enlighter-language="csharp"&gt;using System;
using System.Collections;
using System.Text;

namespace Utility.Web.UI
{
    public class DisableHelper
    {
        /// &amp;lt;summary&amp;gt;
        /// Adds client-side javascript code to disable controls on a submit.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="Page"&amp;gt;Reference to the current page&amp;lt;/param&amp;gt;
        /// &amp;lt;param name="strControls"&amp;gt;String array of client-side control names.&amp;lt;/param&amp;gt;
        public static void DisableCtrlOnSubmit(
            System.Web.UI.Page Page,
            params string[] strControls)
        {
            StringBuilder sbJS = new StringBuilder(200);
            sbJS.Append(@"
&amp;lt;script language=""javascript""&amp;gt;
function MSDisable() {
    try {
        if (Page_IsValid==false) return;
        window.setTimeout('MSDisableCtrls(true)',0);
    } catch (e) {
        window.setTimeout('MSDisableCtrls(true)',0);
    }
}

function MSEnable() {
    try {
        window.setTimeout('MSDisableCtrls(false)',0);
    } catch (e) {
        window.setTimeout('MSDisableCtrls(false)',0);
    }
}
"
                );

            sbJS.Append(@"
function MSDisableCtrls(value) {
"
                );

            foreach (string strControl in strControls)
            {
                sbJS.Append("\ttry { ");
                sbJS.Append(strControl);
                sbJS.Append(".disabled = value;");
                sbJS.Append(" } catch (e) {}\n");
            }

            sbJS.Append(@"
}
&amp;lt;/script&amp;gt;
"
                );

            if (!Page.IsClientScriptBlockRegistered("MSDisableImpl"))
            {
                Page.RegisterClientScriptBlock(
                    "MSDisableImpl",
                    sbJS.ToString());
            }

            Page.RegisterOnSubmitStatement("MSDisable", "MSDisable(false);");
        }

        /// &amp;lt;summary&amp;gt;
        /// Adds client-side javascript code to disable controls on a submit.
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;param name="Page"&amp;gt;Reference to the current page&amp;lt;/param&amp;gt;
        /// &amp;lt;param name="aryClientControlNames"&amp;gt;ArrayList with the client-side control names&amp;lt;/param&amp;gt;
        public static void DisableCtrlOnSubmit(
            System.Web.UI.Page Page,
            ArrayList aryClientControlNames)
        {
            if (aryClientControlNames != null)
            {
                string[] strControls = (string[]) aryClientControlNames.ToArray(typeof(string));
                DisableCtrlOnSubmit(Page, strControls);
            }
        }

        private static void DiableCtrlOnSubmit(
            System.Web.UI.Page Page,
            ArrayList aryClientControlNames)
        {
            DisableCtrlOnSubmit(Page, aryClientControlNames);
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/disabling-fields-on-submit/comments#comments-start</comments><category>ASP.NET</category><category>C#</category></item><item><trackback:ping>http://nimblecoder.com/feed/trackback/462bee57-1755-4f97-9949-ca0733a7a995</trackback:ping><pingback:server>http://nimblecoder.com/feed/pingback</pingback:server><pingback:target>http://nimblecoder.com/post/462bee57-1755-4f97-9949-ca0733a7a995</pingback:target><dc:creator>Ryan Van Slooten</dc:creator><wfw:comment>http://nimblecoder.com/scripting-excel-with-javascript/comments#comments-start</wfw:comment><wfw:commentRss>http://nimblecoder.com/feed/rss/comments/462bee57-1755-4f97-9949-ca0733a7a995</wfw:commentRss><title>Scripting Excel with JavaScript</title><guid isPermaLink="false">http://nimblecoder.com/post/462bee57-1755-4f97-9949-ca0733a7a995</guid><link>http://nimblecoder.com/scripting-excel-with-javascript</link><pubDate>Wed, 25 Apr 2007 19:56:00 GMT</pubDate><description>&lt;div&gt;&lt;p&gt;I vastly prefer Javascript over VBScript for many of the reasons describe by &lt;a href="http://www.joelonsoftware.com/items/2006/08/01.html"&gt;Joel On Software&lt;/a&gt; and by this &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/05/JavaScript/"&gt;MSDN article&lt;/a&gt;. Many projects that I work on use Excel for simple data relationships. Most of the data is so simple that it does not warrant a full SQL database, but a single table (spreadsheet) will suffice. I use the spreadsheets to generate files for multiple systems in some cases. For example, in an embedded turbine governor project&amp;nbsp;I used a spreadsheet to map the tagnames to the communication details (rSpeed1 = 32025). The spreadsheet generated a C source file for the embedded controller, an XML file for the configuration software, and a mapping file for the help documentation. Using the spreadsheet helped keep three distinct systems synchronized.&lt;/p&gt; &lt;p&gt;I still receive a lot of Excel files from customers and I usually need to process and filter the spreadsheets. I receive files with &lt;a href="http://en.wikipedia.org/wiki/Distributed_control_system"&gt;DCS&lt;/a&gt; tag names and I often need to filter the list. The auto-filter in Excel is fine for two or three types, but I usually need to filter based on more than ten regular expression filters. The following is an example of a Javascript file I used to filter the spreadsheet:&lt;/p&gt; &lt;pre class="code enlighter js" data-enlighter-language="js"&gt;// Constants
var INITIAL_ROW = 3;                    // Two rows of header
var DELETED_COLUMN_NAME = "DELETED";
var FILTER_COLUMN_NAME = "INST_NO";
var INCLUDE_COLUMN = [
     "INST_NO"
    ,"PID_SHT"
    ,"INTOOLS__Loop_No"
    ,"INST"
    ,"DESCRP1"
    ,"DESCRP2"
    ,"HI_SCALE"
    ,"ENG_UNITS"
    ,"ALMLL"
    ,"ALML"
    ,"ALMH"
    ,"ALMHH"
    ,"SET_POINT"
];
var INCLUDE_TAGPREFIX = [
    // Analog Inputs
     "AI"
    ,"FI"
    ,"LI"
    ,"PI"
    ,"TI"

    // DCS Calculations
   
    // Controllers
    ,"AC"
    ,"FC"
    ,"LC"
    ,"PC"
    ,"TC"
    ,"AIC"
    ,"FIC"
    ,"LIC"
    ,"PIC"
    ,"TIC"
   
    // Hand Switch PV Flag
    ,"HS"
    ,"PVFL"
];


// Basic Excel object
var Excel = {
    _App : null
    ,_created : false
    ,Constants : {
         pause : 0
        //Excel.XlDeleteShiftDirection
        ,xlShiftToLeft    : 0xFFFFEFC1
        ,xlShiftUp        : 0xFFFFEFBE
    }

    ,newApp : function() {
        this._App = new ActiveXObject("Excel.Application");
        this._created = true;
        return this._App;
    }

    ,getApp : function() {
        this._App = GetObject("","Excel.Application");
        return this._App;
    }

    ,_quit : function() {
        if (this._App)
        {
            this._App.Quit();
            this._created = false;
            this._App = null;
        }
        return;
    }

    ,bye : function() {
        if (this._created)
            this._quit();
        this._App = null;
    }
};


// Load the header row
function getHeaderRow(sheet, table)
{
    if (sheet)
    {
        var row = 1;
        var lastCol = sheet.UsedRange.Columns.Count;

        for (var col = 1; col &amp;lt;= lastCol; ++col)
        {
            var title = "" + sheet.Cells(row, col).Text;
            table[title] = col;
            table["_" + col] = title;
        }
    }
}

function ProcessWorksheet(sheet, rowFunction, map)
{
    if (sheet)
    {
        var lastRow = sheet.UsedRange.Rows.Count;
        var row = INITIAL_ROW;
        while (row &amp;lt;= lastRow)
        {
            // If the row does not match, it is deleted and
            // do not move to the next row as the rows are shifted up.
               if ( rowFunction(sheet, row, map) )
                   ++row;
               else
                   --lastRow;
           }
    }
}

function matchTagPrefixSetup(prefixArray)
{
    var result;
    if (prefixArray)
    {
        result = new Array(prefixArray.length);
        for (var i = 0; i &amp;lt; prefixArray.length; ++i)
        {
            result[i] = new RegExp("^" + prefixArray[i] + "[0-9]");
        }
    }
    return result;
}

// Hide row if it does not match any filter prefix
function processRowFunction(sheet, row, data)
{
    var match = false;
    data.rowsProcessed += 1;
    var text = sheet.Cells(row, data.deleteCol).Value;
    if (!text)
    {
        text = sheet.Cells(row, data.matchCol).Value;
        for (var i = 0; i &amp;lt; data.prefixes.length; ++i)
        {
            var a = data.prefixes[i].exec(text);
            if (a != null)
            {
                match = true;
                break;
            }
        }
    }

    if (!match)
    {
        sheet.Cells(row, data.matchCol).EntireRow.Delete(Excel.Constants.xlShiftUp);
        data.rowsDeleted += 1;
    }
   
    return match;
}

function main(args)
{
    // Attempt to get an open instance of Excel
    var app = Excel.getApp();
    if (app)
        var sheet = app.ActiveSheet;

    if (sheet)
    {
        // Get an array of RegExp for the matching prefixes
        var prefixes = matchTagPrefixSetup(INCLUDE_TAGPREFIX);

        // Get the header row
        var table = new Object();
        getHeaderRow(sheet, table);
        var matchCol = table[FILTER_COLUMN_NAME];
        var deleteCol = table[DELETED_COLUMN_NAME];

        // Build the row process function
        var map =
        {
             "prefixes"        : prefixes
            ,"matchCol"        : matchCol
            ,"deleteCol"       : deleteCol
            ,"rowsProcessed"   : 0
            ,"rowsDeleted"     : 0
            ,"startTime"       : null
            ,"finishTime"      : null
            ,"elapsedTime"     : null
        };

        map.startTime = new Date();

        // Process the worksheet
        app.ScreenUpdating = false;
        ProcessWorksheet(sheet, processRowFunction, map);
        app.ScreenUpdating = true;

        map.finishTime = new Date();
        map.elapsedTime = map.finishTime - map.startTime;
       
        // Statistics
        WScript.Echo("Rows Processed: " + map.rowsProcessed);
        WScript.Echo("Rows Deleted: " + map.rowsDeleted);
        WScript.Echo("Elapsed Time: " + map.elapsedTime / 1000 + " seconds");
    }

    // Cleanup
    sheet = null;
    myApp = null;
    Excel.bye();
}

// Program entry point
main(WScript.Arguments);
&lt;/pre&gt;&lt;/div&gt;</description><comments>http://nimblecoder.com/scripting-excel-with-javascript/comments#comments-start</comments><category>Excel</category><category>JavaScript</category></item></channel></rss>