Created
December 8, 2014 19:29
-
-
Save cartermp/5d0d4105330edd2516eb to your computer and use it in GitHub Desktop.
Converts a Visual Studio XML Documentation File into Equivalent Markdown. Modified from here: https://gist.github.com/lontivero/593fc51f1208555112e0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
using System.Xml; | |
using System.Xml.Linq; | |
namespace WuTang4Eva | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var xml = File.ReadAllText( | |
@"C:\Users\phillip.carter\Documents\Visual Studio 2013\Projects\WuTang4Eva\WuTang4Eva\bin\Debug\WuTang4eva.xml"); | |
var doc = XDocument.Parse(xml); | |
var md = doc.Root.ToMarkDown(); | |
Console.WriteLine(md); | |
string path = @"C:\Users\phillip.carter\Desktop\stuff.md"; | |
if (File.Exists(path)) | |
{ | |
File.Delete(path); | |
} | |
using (var fs = File.Create(path)) | |
{ | |
var info = new UTF8Encoding(true).GetBytes(md); | |
fs.Write(info, 0, info.Length); | |
} | |
} | |
} | |
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 = e as XElement; | |
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], StripNamespaceFromName(vals[0])); | |
break; | |
case 2: | |
str = string.Format(templates[name], StripNamespaceFromName(vals[0]), vals[1]); | |
break; | |
case 3: | |
str = string.Format(templates[name], StripNamespaceFromName(vals[0]), vals[1], vals[2]); | |
break; | |
case 4: str = | |
string.Format(templates[name], vals[0], StripNamespaceFromName(vals[0]), vals[2], vals[3]); | |
break; | |
} | |
return str; | |
} | |
if (e.NodeType == XmlNodeType.Text) | |
{ | |
return Regex.Replace((e as XText).Value.Replace('\n', ' '), @"\s+", " "); | |
} | |
return ""; | |
} | |
internal static string ToMarkDown(this IEnumerable<XNode> es) | |
{ | |
return es.Aggregate("", (current, x) => current + x.ToMarkDown()); | |
} | |
// Strips the silly Namespace generated by the assembly. | |
internal static string StripNamespaceFromName(string namespacedElement) | |
{ | |
int parenIdx = namespacedElement.IndexOf('('); | |
int lastDotIdx = 0; | |
if (parenIdx > 0) | |
{ | |
string subs = namespacedElement.Substring(0, parenIdx); | |
lastDotIdx = subs.LastIndexOf('.'); | |
} | |
else if (namespacedElement[1] == ':') | |
{ | |
lastDotIdx = namespacedElement.LastIndexOf('.'); | |
} | |
else | |
{ | |
return namespacedElement; | |
} | |
return string.Join("", namespacedElement.Skip(lastDotIdx + 1)); | |
} | |
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()))); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment