2 using System.Collections;
3 using System.Collections.Generic;
5 using System.Reflection;
8 using System.Xml.XPath;
10 using Mono.Documentation;
13 [assembly: AssemblyTitle("Monodocs-to-HTML")]
14 [assembly: AssemblyCopyright("Copyright (c) 2004 Joshua Tauberer <tauberer@for.net>, released under the GPL.")]
15 [assembly: AssemblyDescription("Convert Monodoc XML documentation to static HTML.")]
17 namespace Mono.Documentation {
19 class MDocToHtmlConverterOptions {
22 public string ext = "html";
23 public string onlytype;
24 public string template;
25 public bool dumptemplate;
28 class MDocToHtmlConverter : MDocCommand {
30 public override void Run (IEnumerable<string> args)
32 opts = new MDocToHtmlConverterOptions ();
33 var p = new OptionSet () {
35 "Writes the default XSLT to stdout.",
36 v => opts.dumptemplate = v != null },
38 "The file {EXTENSION} to use for created files. "+
39 "This defaults to \"html\".",
42 "The {DIRECTORY} to place the generated files and directories.",
45 "An XSLT {FILE} to use to generate the created " +
46 "files. If not specified, uses the template generated by " +
47 "--default-template.",
48 v => opts.template = v },
50 List<string> extra = Parse (p, args, "export-html",
51 "[OPTIONS]+ DIRECTORIES",
52 "Export mdoc documentation within DIRECTORIES to HTML.");
57 foreach (var source in extra) {
61 opts.onlytype = "ignore"; // remove warning about unused member
64 static MDocToHtmlConverterOptions opts;
66 private static void Main2()
68 if (opts.dumptemplate) {
73 if (opts.source == null || opts.source == "" || opts.dest == null || opts.dest == "")
74 throw new ApplicationException("The source and dest options must be specified.");
76 Directory.CreateDirectory(opts.dest);
78 // Load the stylesheets, overview.xml, and resolver
80 XslTransform overviewxsl = LoadTransform("overview.xsl");
81 XslTransform stylesheet = LoadTransform("stylesheet.xsl");
82 XslTransform template;
83 if (opts.template == null) {
84 template = LoadTransform("defaulttemplate.xsl");
87 XmlDocument templatexsl = new XmlDocument();
88 templatexsl.Load(opts.template);
89 template = new XslTransform();
90 template.Load(templatexsl);
91 } catch (Exception e) {
92 throw new ApplicationException("There was an error loading " + opts.template, e);
96 XmlDocument overview = new XmlDocument();
97 overview.Load(opts.source + "/index.xml");
99 ArrayList extensions = GetExtensionMethods (overview);
101 // Create the master page
102 XsltArgumentList overviewargs = new XsltArgumentList();
103 overviewargs.AddParam("ext", "", opts.ext);
104 overviewargs.AddParam("basepath", "", "./");
105 Generate(overview, overviewxsl, overviewargs, opts.dest + "/index." + opts.ext, template);
106 overviewargs.RemoveParam("basepath", "");
107 overviewargs.AddParam("basepath", "", "../");
109 // Create the namespace & type pages
111 XsltArgumentList typeargs = new XsltArgumentList();
112 typeargs.AddParam("ext", "", opts.ext);
113 typeargs.AddParam("basepath", "", "../");
115 foreach (XmlElement ns in overview.SelectNodes("Overview/Types/Namespace")) {
116 string nsname = ns.GetAttribute("Name");
118 if (opts.onlytype != null && !opts.onlytype.StartsWith(nsname + "."))
121 System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(opts.dest + "/" + nsname);
122 if (!d.Exists) d.Create();
124 // Create the NS page
125 overviewargs.AddParam("namespace", "", nsname);
126 Generate(overview, overviewxsl, overviewargs, opts.dest + "/" + nsname + "/index." + opts.ext, template);
127 overviewargs.RemoveParam("namespace", "");
129 foreach (XmlElement ty in ns.SelectNodes("Type")) {
130 string typefilebase = ty.GetAttribute("Name");
131 string typename = ty.GetAttribute("DisplayName");
132 if (typename.Length == 0)
133 typename = typefilebase;
135 if (opts.onlytype != null && !(nsname + "." + typename).StartsWith(opts.onlytype))
138 string typefile = opts.source + "/" + nsname + "/" + typefilebase + ".xml";
139 if (!File.Exists(typefile)) continue;
141 XmlDocument typexml = new XmlDocument();
142 typexml.Load(typefile);
143 if (extensions != null) {
144 DocLoader loader = CreateDocLoader (overview);
145 XmlDocUtils.AddExtensionMethods (typexml, extensions, loader);
148 Console.WriteLine(nsname + "." + typename);
150 Generate(typexml, stylesheet, typeargs, opts.dest + "/" + nsname + "/" + typefilebase + "." + opts.ext, template);
155 private static ArrayList GetExtensionMethods (XmlDocument doc)
157 XmlNodeList extensions = doc.SelectNodes ("/Overview/ExtensionMethods/*");
158 if (extensions.Count == 0)
160 ArrayList r = new ArrayList (extensions.Count);
161 foreach (XmlNode n in extensions)
166 private static void DumpTemplate() {
167 Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("defaulttemplate.xsl");
168 Stream o = Console.OpenStandardOutput ();
169 byte[] buf = new byte[1024];
171 while ((r = s.Read (buf, 0, buf.Length)) > 0) {
176 private static void Generate(XmlDocument source, XslTransform transform, XsltArgumentList args, string output, XslTransform template) {
177 using (TextWriter textwriter = new StreamWriter(new FileStream(output, FileMode.Create))) {
178 XmlTextWriter writer = new XmlTextWriter(textwriter);
179 writer.Formatting = Formatting.Indented;
180 writer.Indentation = 2;
181 writer.IndentChar = ' ';
184 XmlDocument intermediate = new XmlDocument();
185 intermediate.PreserveWhitespace = true;
186 intermediate.Load(transform.Transform(source, args, new ManifestResourceResolver(opts.source)));
187 template.Transform(intermediate, new XsltArgumentList(), new XhtmlWriter (writer), null);
188 } catch (Exception e) {
189 throw new ApplicationException("An error occured while generating " + output, e);
194 private static XslTransform LoadTransform(string name) {
196 XmlDocument xsl = new XmlDocument();
197 xsl.Load(Assembly.GetExecutingAssembly().GetManifestResourceStream(name));
199 if (name == "overview.xsl") {
200 // bit of a hack. overview needs the templates in stylesheet
201 // for doc formatting, and rather than write a resolver, I'll
202 // just do the import for it.
204 XmlNode importnode = xsl.DocumentElement.SelectSingleNode("*[name()='xsl:include']");
205 xsl.DocumentElement.RemoveChild(importnode);
207 XmlDocument xsl2 = new XmlDocument();
208 xsl2.Load(Assembly.GetExecutingAssembly().GetManifestResourceStream("stylesheet.xsl"));
209 foreach (XmlNode node in xsl2.DocumentElement.ChildNodes)
210 xsl.DocumentElement.AppendChild(xsl.ImportNode(node, true));
213 XslTransform t = new XslTransform();
214 t.Load (xsl, new ManifestResourceResolver (opts.source));
217 } catch (Exception e) {
218 throw new ApplicationException("Error loading " + name + " from internal resource", e);
222 private static DocLoader CreateDocLoader (XmlDocument overview)
224 Hashtable docs = new Hashtable ();
225 DocLoader loader = delegate (string s) {
226 XmlDocument d = null;
227 if (!docs.ContainsKey (s)) {
228 foreach (XmlNode n in overview.SelectNodes ("//Type")) {
229 string ns = n.ParentNode.Attributes ["Name"].Value;
230 string t = n.Attributes ["Name"].Value;
231 if (s == ns + "." + t.Replace ("+", ".")) {
232 string f = opts.source + "/" + ns + "/" + t + ".xml";
233 if (File.Exists (f)) {
234 d = new XmlDocument ();
243 d = (XmlDocument) docs [s];