// // The ecmaspec provider is for ECMA specifications // // Authors: // John Luke (jluke@cfl.rr.com) // Ben Maurer (bmaurer@users.sourceforge.net) // // Use like this: // mono assembler.exe --ecmaspec DIRECTORY --out name // namespace Monodoc { using System; using System.Diagnostics; using System.IO; using System.Text; using System.Xml.XPath; using System.Xml.Xsl; using System.Xml; using System.Collections; using Mono.Lucene.Net.Index; using Mono.Lucene.Net.Documents; public class EcmaSpecProvider : Provider { string basedir; public EcmaSpecProvider (string base_directory) { basedir = base_directory; if (!Directory.Exists (basedir)) throw new FileNotFoundException (String.Format ("The directory `{0}' does not exist", basedir)); } public override void PopulateTree (Tree tree) { XPathNavigator n = new XPathDocument (Path.Combine (basedir, "toc.xml")).CreateNavigator (); n.MoveToRoot (); n.MoveToFirstChild (); PopulateNode (n.SelectChildren ("node", ""), tree); } void PopulateNode (XPathNodeIterator nodes, Node treeNode) { while (nodes.MoveNext ()) { XPathNavigator n = nodes.Current; string secNumber = n.GetAttribute ("number", ""), secName = n.GetAttribute ("name", ""); treeNode.tree.HelpSource.Message (TraceLevel.Info, "\tSection: " + secNumber); treeNode.tree.HelpSource.PackFile (Path.Combine (basedir, secNumber + ".xml"), secNumber); Node thisNode = treeNode.LookupNode (secNumber + ": " + secName, "ecmaspec:" + secNumber); if (n.HasChildren) PopulateNode (n.SelectChildren ("node", ""), thisNode); } } public override void CloseTree (HelpSource hs, Tree tree) { } } public class EcmaSpecHelpSource : HelpSource { public EcmaSpecHelpSource (string base_file, bool create) : base (base_file, create) { } public override string InlineCss { get {return base.InlineCss + css_ecmaspec_code;} } public override string GetText (string url, out Node match_node) { string ret = null; match_node = null; if (url.StartsWith ("ecmaspec:")) { match_node = MatchNode (Tree, url); ret = GetTextFromUrl (url); } if (url == "root:") { if (use_css) ret = "
C# Language Specification
"; else ret = "

C# Language Specification

"; match_node = Tree; } if (ret != null && match_node != null && match_node.Nodes != null && match_node.Nodes.Count > 0) { ret += "

In This Section:

\n"; } if (ret != null) return BuildHtml (css_ecmaspec_code, ret); else return null; } private Node MatchNode (Node node, string matchurl) { foreach (Node n in node.Nodes) { if (matchurl == n.Element) return n; else if (matchurl.StartsWith (n.Element + ".") && !n.IsLeaf) return MatchNode (n, matchurl); } return null; } string GetTextFromUrl (string url) { Stream file_stream = GetHelpStream (url.Substring (9)); if (file_stream == null) return null; return Htmlize (new XPathDocument (file_stream)); } static string css_ecmaspec; public static string css_ecmaspec_code { get { if (css_ecmaspec != null) return css_ecmaspec; if (use_css) { System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly (); Stream str_css = assembly.GetManifestResourceStream ("ecmaspec.css"); css_ecmaspec = (new StreamReader (str_css)).ReadToEnd(); } else { css_ecmaspec = String.Empty; } return css_ecmaspec; } } class ExtObj { public string Colorize (string code, string lang) { return (Mono.Utilities.Colorizer.Colorize(code,lang)); } } static XslTransform ecma_transform; static XsltArgumentList args = new XsltArgumentList(); static string Htmlize (XPathDocument ecma_xml) { if (ecma_transform == null){ ecma_transform = new XslTransform (); System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly (); Stream stream; if (use_css) stream = assembly.GetManifestResourceStream ("ecmaspec-html-css.xsl"); else stream = assembly.GetManifestResourceStream ("ecmaspec-html.xsl"); XmlReader xml_reader = new XmlTextReader (stream); ecma_transform.Load (xml_reader, null, null); args.AddExtensionObject ("monodoc:///extensions", new ExtObj()); } if (ecma_xml == null) return ""; StringWriter output = new StringWriter (); ecma_transform.Transform (ecma_xml, args, output, null); return output.ToString (); } public override void PopulateSearchableIndex (IndexWriter writer) { foreach (Node n in Tree.Nodes) AddDocuments (writer, n); } void AddDocuments (IndexWriter writer, Node node) { string url = node.URL; Stream file_stream = GetHelpStream (url.Substring (9)); if (file_stream == null) //Error return; XmlDocument xdoc = new XmlDocument (); xdoc.Load (new XmlTextReader (file_stream)); //Obtain the title XmlNode nelem = xdoc.DocumentElement; string title = nelem.Attributes["number"].Value + ": " + nelem.Attributes["title"].Value; //Obtain the text StringBuilder s = new StringBuilder (); GetTextNode (nelem, s); string text = s.ToString (); //Obatin the examples StringBuilder s2 = new StringBuilder (); GetExamples (nelem, s2); string examples = s2.ToString (); //Write to the Lucene Index all the parts SearchableDocument doc = new SearchableDocument (); doc.title = title; doc.hottext = title.Substring (title.IndexOf (':')); doc.url = url; doc.text = text; doc.examples = examples; writer.AddDocument (doc.LuceneDoc); if (node.IsLeaf) return; foreach (Node n in node.Nodes) AddDocuments (writer, n); } void GetTextNode (XmlNode n, StringBuilder s) { //dont include c# code if (n.Name == "code_example") return; //include all text from nodes if (n.NodeType == XmlNodeType.Text) s.Append (n.Value); //recursively explore all nodes if (n.HasChildNodes) foreach (XmlNode n_child in n.ChildNodes) GetTextNode (n_child, s); } void GetExamples (XmlNode n, StringBuilder s) { if (n.Name == "code_example") { if (n.FirstChild.Name == "#cdata-section") s.Append (n.FirstChild.Value); } else { if (n.HasChildNodes) foreach (XmlNode n_child in n.ChildNodes) GetExamples (n_child, s); } } } }