Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generates Markdown from VS XML documentation file
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
namespace GithubWikiDoc
{
class Program
{
static void Main(string[] args)
{
var xml = File.ReadAllText(args[0]);
var doc = XDocument.Parse(xml);
var md = doc.Root.ToMarkDown();
Console.WriteLine(md);
}
}
static class XmlToMarkdown
{
internal static string ToMarkDown(this XNode e)
{
var templates = new Dictionary<string, string>
{
{"doc", "## {0} ##\n\n{1}\n\n"},
{"type", "# {0}\n\n{1}\n\n---\n"},
{"field", "##### {0}\n\n{1}\n\n---\n"},
{"property", "##### {0}\n\n{1}\n\n---\n"},
{"method", "##### {0}\n\n{1}\n\n---\n"},
{"event", "##### {0}\n\n{1}\n\n---\n"},
{"summary", "{0}\n\n"},
{"remarks", "\n\n>{0}\n\n"},
{"example", "_C# code_\n\n```c#\n{0}\n```\n\n"},
{"seePage", "[[{1}|{0}]]"},
{"seeAnchor", "[{1}]({0})"},
{"param", "|Name | Description |\n|-----|------|\n|{0}: |{1}|\n" },
{"exception", "[[{0}|{0}]]: {1}\n\n" },
{"returns", "Returns: {0}\n\n"},
{"none", ""}
};
var d = new Func<string, XElement, string[]>((att, node) => new[]
{
node.Attribute(att).Value,
node.Nodes().ToMarkDown()
});
var methods = new Dictionary<string, Func<XElement, IEnumerable<string>>>
{
{"doc", x=> new[]{
x.Element("assembly").Element("name").Value,
x.Element("members").Elements("member").ToMarkDown()
}},
{"type", x=>d("name", x)},
{"field", x=> d("name", x)},
{"property", x=> d("name", x)},
{"method",x=>d("name", x)},
{"event", x=>d("name", x)},
{"summary", x=> new[]{ x.Nodes().ToMarkDown() }},
{"remarks", x => new[]{x.Nodes().ToMarkDown()}},
{"example", x => new[]{x.Value.ToCodeBlock()}},
{"seePage", x=> d("cref", x) },
{"seeAnchor", x=> { var xx = d("cref", x); xx[0] = xx[0].ToLower(); return xx; }},
{"param", x => d("name", x) },
{"exception", x => d("cref", x) },
{"returns", x => new[]{x.Nodes().ToMarkDown()}},
{"none", x => new string[0]}
};
string name;
if(e.NodeType== XmlNodeType.Element)
{
var el = (XElement) e;
name = el.Name.LocalName;
if (name == "member")
{
switch (el.Attribute("name").Value[0])
{
case 'F': name = "field"; break;
case 'P': name = "property"; break;
case 'T': name = "type"; break;
case 'E': name = "event"; break;
case 'M': name = "method"; break;
default: name = "none"; break;
}
}
if(name == "see")
{
var anchor = el.Attribute("cref").Value.StartsWith("!:#");
name = anchor ? "seeAnchor" : "seePage";
}
var vals = methods[name](el).ToArray();
string str="";
switch (vals.Length)
{
case 1: str= string.Format(templates[name], vals[0]);break;
case 2: str= string.Format(templates[name], vals[0],vals[1]);break;
case 3: str= string.Format(templates[name], vals[0],vals[1],vals[2]);break;
case 4: str= string.Format(templates[name], vals[0], vals[1], vals[2], vals[3]);break;
}
return str;
}
if(e.NodeType==XmlNodeType.Text)
return Regex.Replace( ((XText)e).Value.Replace('\n', ' '), @"\s+", " ");
return "";
}
internal static string ToMarkDown(this IEnumerable<XNode> es)
{
return es.Aggregate("", (current, x) => current + x.ToMarkDown());
}
static string ToCodeBlock(this string s)
{
var lines = s.Split(new char[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
var blank = lines[0].TakeWhile(x => x == ' ').Count() - 4;
return string.Join("\n",lines.Select(x => new string(x.SkipWhile((y, i) => i < blank).ToArray())));
}
}
}
@Pxtl

This comment has been minimized.

Copy link

Pxtl commented May 13, 2016

I've taken this thing and built a NuGet package that sets it up as a build target. Every build you will automatically get your .md file regenerated.

https://github.com/Pxtl/XmlCommentMarkDownGenerator

Patches and insults welcome.

@tjfritch

This comment has been minimized.

Copy link

tjfritch commented Jun 27, 2018

This has some great potential! Any chance you could add support for additional valid tags? For example, paramref and typeparam appear to be unsupported and result in exceptions. Thanks!

@bradfriedlander

This comment has been minimized.

Copy link

bradfriedlander commented Oct 5, 2018

I've created an updated version of this code that includes the rest of the C# documentation tags and generates most of them in a 'decent" format. I could update this code (if there is a repository for it) or create a new one on GitHub.

Is anyone interested and does anyone have a good suggestion?

@tom-corwin

This comment has been minimized.

Copy link

tom-corwin commented Oct 13, 2018

@bradfriedlander I'm going to be writing a tool like this for my project, so I'm interested in the updated version if it's available. 🙂

EDIT: Fixed the project link. Whoops.

@zspitz

This comment has been minimized.

Copy link

zspitz commented Feb 8, 2019

@bradfriedlander I would be interested in your updated version.

@loxsmoke

This comment has been minimized.

Copy link

loxsmoke commented Feb 15, 2019

Take a look at DocXml project. There is a sample markdown documentation generator in the repo.

@aggsol

This comment has been minimized.

Copy link

aggsol commented Nov 13, 2019

@loxsmoke

Take a look at DocXml project. There is a sample markdown documentation generator in the repo.

I can't find anything markdown there.

@loxsmoke

This comment has been minimized.

Copy link

loxsmoke commented Nov 26, 2019

Sample became a .net core global tool. See here mddox

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.