2 using System.Collections;
4 using System.Reflection;
7 using System.Xml.XPath;
10 using Mono.Documentation;
12 [assembly: AssemblyTitle("Monodocs-to-HTML")]
13 [assembly: AssemblyCopyright("Copyright (c) 2004 Joshua Tauberer <tauberer@for.net>, released under the GPL.")]
14 [assembly: AssemblyDescription("Convert Monodoc XML documentation to static HTML.")]
16 [assembly: Mono.UsageComplement("")]
18 public class Monodocs2HTML {
20 private class Opts : Options {
21 [Option("The base directory of the XML documentation")]
24 [Option("The output directory of the XML documentation")]
27 [Option("The file extension for generated files (default 'html')")]
28 public string ext = "html";
30 [Option("Only update the given type")]
31 public string onlytype;
33 [Option("Use the given page template")]
34 public string template;
36 [Option("Dump the default page template to standard out so you may copy it to make a new template for the --template option.")]
37 public bool dumptemplate;
40 static Opts opts = new Opts();
42 public static void Main(string[] args) {
44 opts.ProcessArgs(args);
46 } catch (ApplicationException appex) {
49 Console.Error.WriteLine(e.Message);
55 private static void Main2() {
56 if (opts.dumptemplate) {
61 if (opts.source == null || opts.source == "" || opts.dest == null || opts.dest == "")
62 throw new ApplicationException("The source and dest options must be specified.");
64 Directory.CreateDirectory(opts.dest);
66 // Load the stylesheets, overview.xml, and resolver
68 XslTransform overviewxsl = LoadTransform("overview.xsl");
69 XslTransform stylesheet = LoadTransform("stylesheet.xsl");
70 XslTransform template;
71 if (opts.template == null) {
72 template = LoadTransform("defaulttemplate.xsl");
75 XmlDocument templatexsl = new XmlDocument();
76 templatexsl.Load(opts.template);
77 template = new XslTransform();
78 template.Load(templatexsl);
79 } catch (Exception e) {
80 throw new ApplicationException("There was an error loading " + opts.template, e);
84 XmlDocument overview = new XmlDocument();
85 overview.Load(opts.source + "/index.xml");
87 ArrayList extensions = GetExtensionMethods (overview);
89 // Create the master page
90 XsltArgumentList overviewargs = new XsltArgumentList();
91 overviewargs.AddParam("ext", "", opts.ext);
92 overviewargs.AddParam("basepath", "", "./");
93 Generate(overview, overviewxsl, overviewargs, opts.dest + "/index." + opts.ext, template);
94 overviewargs.RemoveParam("basepath", "");
95 overviewargs.AddParam("basepath", "", "../");
97 // Create the namespace & type pages
99 XsltArgumentList typeargs = new XsltArgumentList();
100 typeargs.AddParam("ext", "", opts.ext);
101 typeargs.AddParam("basepath", "", "../");
103 foreach (XmlElement ns in overview.SelectNodes("Overview/Types/Namespace")) {
104 string nsname = ns.GetAttribute("Name");
106 if (opts.onlytype != null && !opts.onlytype.StartsWith(nsname + "."))
109 System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(opts.dest + "/" + nsname);
110 if (!d.Exists) d.Create();
112 // Create the NS page
113 overviewargs.AddParam("namespace", "", nsname);
114 Generate(overview, overviewxsl, overviewargs, opts.dest + "/" + nsname + "/index." + opts.ext, template);
115 overviewargs.RemoveParam("namespace", "");
117 foreach (XmlElement ty in ns.SelectNodes("Type")) {
118 string typefilebase = ty.GetAttribute("Name");
119 string typename = ty.GetAttribute("DisplayName");
120 if (typename.Length == 0)
121 typename = typefilebase;
123 if (opts.onlytype != null && !(nsname + "." + typename).StartsWith(opts.onlytype))
126 string typefile = opts.source + "/" + nsname + "/" + typefilebase + ".xml";
127 if (!File.Exists(typefile)) continue;
129 XmlDocument typexml = new XmlDocument();
130 typexml.Load(typefile);
131 if (extensions != null) {
132 DocLoader loader = CreateDocLoader (overview);
133 XmlDocUtils.AddExtensionMethods (typexml, extensions, loader);
136 Console.WriteLine(nsname + "." + typename);
138 Generate(typexml, stylesheet, typeargs, opts.dest + "/" + nsname + "/" + typefilebase + "." + opts.ext, template);
143 private static ArrayList GetExtensionMethods (XmlDocument doc)
145 XmlNodeList extensions = doc.SelectNodes ("/Overview/ExtensionMethods/*");
146 if (extensions.Count == 0)
148 ArrayList r = new ArrayList (extensions.Count);
149 foreach (XmlNode n in extensions)
154 private static void DumpTemplate() {
155 Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("defaulttemplate.xsl");
156 Stream o = Console.OpenStandardOutput ();
157 byte[] buf = new byte[1024];
159 while ((r = s.Read (buf, 0, buf.Length)) > 0) {
164 private static void Generate(XmlDocument source, XslTransform transform, XsltArgumentList args, string output, XslTransform template) {
165 using (TextWriter textwriter = new StreamWriter(new FileStream(output, FileMode.Create))) {
166 XmlTextWriter writer = new XmlTextWriter(textwriter);
167 writer.Formatting = Formatting.Indented;
168 writer.Indentation = 2;
169 writer.IndentChar = ' ';
172 XmlDocument intermediate = new XmlDocument();
173 intermediate.PreserveWhitespace = true;
174 intermediate.Load(transform.Transform(source, args, new ManifestResourceResolver(opts.source)));
175 template.Transform(intermediate, new XsltArgumentList(), new XhtmlWriter (writer), null);
176 } catch (Exception e) {
177 throw new ApplicationException("An error occured while generating " + output, e);
182 private static XslTransform LoadTransform(string name) {
184 XmlDocument xsl = new XmlDocument();
185 xsl.Load(Assembly.GetExecutingAssembly().GetManifestResourceStream(name));
187 if (name == "overview.xsl") {
188 // bit of a hack. overview needs the templates in stylesheet
189 // for doc formatting, and rather than write a resolver, I'll
190 // just do the import for it.
192 XmlNode importnode = xsl.DocumentElement.SelectSingleNode("*[name()='xsl:include']");
193 xsl.DocumentElement.RemoveChild(importnode);
195 XmlDocument xsl2 = new XmlDocument();
196 xsl2.Load(Assembly.GetExecutingAssembly().GetManifestResourceStream("stylesheet.xsl"));
197 foreach (XmlNode node in xsl2.DocumentElement.ChildNodes)
198 xsl.DocumentElement.AppendChild(xsl.ImportNode(node, true));
201 XslTransform t = new XslTransform();
202 t.Load (xsl, new ManifestResourceResolver (opts.source));
205 } catch (Exception e) {
206 throw new ApplicationException("Error loading " + name + " from internal resource", e);
210 private static DocLoader CreateDocLoader (XmlDocument overview)
212 Hashtable docs = new Hashtable ();
213 DocLoader loader = delegate (string s) {
214 XmlDocument d = null;
215 if (!docs.ContainsKey (s)) {
216 foreach (XmlNode n in overview.SelectNodes ("//Type")) {
217 string ns = n.ParentNode.Attributes ["Name"].Value;
218 string t = n.Attributes ["Name"].Value;
219 if (s == ns + "." + t.Replace ("+", ".")) {
220 string f = opts.source + "/" + ns + "/" + t + ".xml";
221 if (File.Exists (f)) {
222 d = new XmlDocument ();
231 d = (XmlDocument) docs [s];