Xml Documenter Macro#

Although I've argued before that Typed DataSets aren't evil, there's one thing that bothers me a lot when dealing with them in a library project: the code that gets generated doesn't contain any XML comments. In itself, that isn't so bad (after all, which useful comments could be generated from an XSD schema?), but if the project is configured to emit an XML documentation file, you get a gazillion warnings for each member that lacks a comment. I like to keep my build warning-free to avoid "known harmless warnings" from hiding "new and important warnings" (if I can first get my stuff to build without errors, at least). You could go about and put comments on the generated file manually, but any change on the dataset's schema file will trigger the code to be regenerated so you've lost all your hard work. Hence I created the following quick and dirty solution: a Visual Studio macro that runs over all members and puts a placeholder comment (containing just the member's name) on top. Anytime the code gets regenerated, just run the macro and you're set. I'm sure this should be able to run as a post-build step or something too, but if you're lazy like me (and you're a programmer too, so you're lazy by definition), you'll already be happy you got this done.

Oh, and if you're really lazy, you can use this macro to document all your members automatically - although I'd add some random word-generator to make it look just a little more convincing (to fool the QA-guys at least).

So here's the source (with special thanks to the MSDN article on XML Comment Macros):

Imports EnvDTE
Imports System.Diagnostics
Imports System
Imports System.Xml
Imports System.IO
Imports System.Collections
Imports System.Text
Imports System.Text.RegularExpressions

Public Module XmlDocumenter

    Public Sub InsertGenericSummaries()

        SetCommentsRecursively(DTE.ActiveDocument.ProjectItem.FileCodeModel.CodeElements)

    End Sub

    Private Sub SetCommentsRecursively(ByVal elements As CodeElements)

        For Each element As CodeElement In elements
            ' Get a comment block.
            Dim doc As XmlDocument = GetCommentXml(element)
            Dim summaryTag As XmlElement = doc.SelectSingleNode("/doc/summary")
            If summaryTag Is Nothing Then
                ' Create <summary> tag
                summaryTag = doc.CreateElement("summary")
                summaryTag.InnerXml = element.Name
                doc.FirstChild.PrependChild(summaryTag)
            End If
            SetCommentXml(element, doc)

            ' Recurse over members.
            Try
                SetCommentsRecursively(element.Members)
            Catch ex As Exception
                ' Ignore exceptions (quick and dirty hack to skip elements that have no Members property)
            End Try
        Next

    End Sub

    ' Code borrowed from http://msdn.microsoft.com/msdnmag/issues/05/07/XMLComments/default.aspx
    Private Sub SetCommentXml(ByVal element As CodeElement, ByVal doc As XmlDocument)
        Dim sb As StringBuilder = New StringBuilder
        Dim sw As StringWriter = New StringWriter(sb)
        Dim xw As XmlTextWriter = New XmlTextWriter(sw)

        Try
            xw.Indentation = 1
            xw.IndentChar = Char.Parse(vbTab)
            xw.Formatting = Formatting.Indented

            Dim rootNode As XmlNode
            If element.Language = CodeModelLanguageConstants.vsCMLanguageVB Then
                rootNode = doc.FirstChild
            Else ' CSharp
                rootNode = doc
            End If

            rootNode.WriteContentTo(xw)
            Try
                element.DocComment = sb.ToString()
            Catch ex As Exception
                ' Ignore
            End Try
        Finally
            xw.Close()
            sw.Close()
        End Try
    End Sub

    ' Code borrowed from http://msdn.microsoft.com/msdnmag/issues/05/07/XMLComments/default.aspx
    Private Function GetCommentXml(ByVal element As CodeElement) As XmlDocument

        Dim doc As XmlDocument = New XmlDocument

        Dim xmlStr As String = element.DocComment
        If Not xmlStr Is Nothing AndAlso xmlStr.Trim() <> String.Empty Then
            If xmlStr.StartsWith("<doc>") = False Then
                ' Ensure single root node
                xmlStr = "<doc>" & xmlStr + "</doc>"
            End If
            xmlStr = Regex.Replace(xmlStr, "^(\s*<doc>\s*){2,}", "<doc>")
            xmlStr = Regex.Replace(xmlStr, "(\s*<\/doc>\s*){2,}$", "</doc>")
            doc.LoadXml(xmlStr)
        Else
            Dim rootTag = doc.CreateElement("doc")
            doc.AppendChild(rootTag)
        End If

        Return doc
    End Function

End Module

Easy, effective, and ugly. Use at your own risk, it might eat your lunch sandwich.

Blog | Programming | .NET | VS.NET | Samples
Monday, January 16, 2006 8:49:00 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

All content © 2010, Jelle Druyts
On this page
Xml Documenter Macro

Recent Photos
www.flickr.com
This is a Flickr badge showing public photos from Jelle Druyts. Make your own badge here.
Advertising
Top Picks
Statistics
Total Posts: 350
This Year: 4
This Month: 2
This Week: 2
Comments: 526
Archives
Sitemap
Disclaimer
This is my personal website, not my boss', not my mother's, and certainly not the pope's. My personal opinions may be irrelevant, inaccurate, boring or even plain wrong, I'm sorry if that makes you feel uncomfortable. But then again, you don't have to read them, I just hope you'll find something interesting here now and then. I'll certainly do my best. But if you don't like it, go read the pope's blog. I'm sure it's fascinating.

Powered by:
newtelligence dasBlog 2.0.7226.0

Sign In