// // A provider that uses Windows help file xhtml TOC files and looks for the // referenced documents to create the help source. // // Authors: // Copyright 2003 Lee Mallabone // Johannes Roith // Miguel de Icaza using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Linq; namespace Monodoc.Providers { public class XhtmlProvider : Provider { string tocFile; readonly XNamespace ns = "http://www.w3.org/1999/xhtml"; public XhtmlProvider (string handbookTocFile) { tocFile = handbookTocFile; if (!File.Exists (tocFile)) throw new FileNotFoundException (String.Format ("The table of contents, `{0}' does not exist", tocFile)); } public override void PopulateTree (Tree tree) { var doc = XDocument.Load (tocFile); var uls = doc.Descendants (ns + "body").First ().Elements (ns + "ul"); foreach (var ul in uls) ParseUl (tree, tree.RootNode, ul); } void ParseUl (Tree tree, Node parent, XElement ul) { var storage = tree.HelpSource.Storage; foreach (var e in ul.Elements (ns + "li")) { var inner = e.Element (ns + "object"); if (inner == null) continue; string caption, element; ObjectEntryToParams (inner, out caption, out element); // Don't add if the backing file doesn't exist if (!File.Exists (element)) { Console.Error.WriteLine ("Warning: File `{0}' referenced in TOC but it doesn't exist. It will be ignored.", element); continue; } using (var file = File.OpenRead (element)) storage.Store (element, file); parent.CreateNode (caption, XhtmlHelpSource.XhtmlPrefix + element); } } void ObjectEntryToParams (XElement obj, out string caption, out string element) { var ps = obj.Elements (ns + "param"); caption = ps .Where (p => p.Attribute ("name").Value == "Name") .Select (p => (string)p.Attribute ("value")) .FirstOrDefault (); caption = caption ?? string.Empty; element = ps .Where (p => p.Attribute ("name").Value == "Local") .Select (p => (string)p.Attribute ("value")) .FirstOrDefault (); element = element ?? string.Empty; } public override void CloseTree (HelpSource hs, Tree tree) { } } public class XhtmlHelpSource : HelpSource { public XhtmlHelpSource (string base_file, bool create) : base (base_file, create) { } internal const string XhtmlPrefix = "xhtml:"; protected override string UriPrefix { get { return XhtmlPrefix; } } public override SortType SortType { get { return SortType.Element; } } public override DocumentType GetDocumentTypeForId (string id) { return id == "root:" ? DocumentType.TocXml : DocumentType.MonoBook; } public override bool IsGeneratedContent (string id) { return id == "root:"; } public override string GetText (string url) { return TreeDumper.ExportToTocXml (Tree.RootNode, "Mono Handbook", string.Empty); } public static string GetAbsoluteLink(string target, string url) { string value = null; if (target.StartsWith ("#") || target.StartsWith ("T:") || target.StartsWith ("M:") || target.StartsWith ("P:") || target.StartsWith ("T:") || target.StartsWith ("E:") || target.StartsWith ("F:") || target.StartsWith ("O:") || target.StartsWith ("N:") || target.StartsWith ("api:")) return null; int endp = target.IndexOf(':'); if (endp == -1) endp = 0; string protocol = target.Substring(0, endp); switch (protocol) { case "mailto": case "http": case "https": case "ftp": case "news": case "irc": break; default: // handle absolute urls like: /html/en/images/empty.png if (!target.StartsWith("/")) { // url is something like "gnome/bindings/mono.html" // This will get the path "gnome/bindings" int slash = url.LastIndexOf ("/"); string tmpurl = url; if (slash != -1) tmpurl = url.Substring(0, slash); // Count "../" in target and go one level down // for each in tmpurl, eventually, then remove "../". Regex reg1 = new Regex("../"); MatchCollection matches = reg1.Matches(target); for(int i = 1; i < matches.Count; i++) { slash = tmpurl.LastIndexOf ("/"); if (slash != -1) tmpurl = tmpurl.Substring(0, slash); } target = target.Replace("../", ""); value = tmpurl + "/" + target; } else { value = target.Substring(1, target.Length - 1); } break; } return value; } XmlDocument RewriteLinks(XmlDocument docToProcess, string url) { XmlNodeList nodeList = docToProcess.GetElementsByTagName("a"); foreach(XmlNode node in nodeList) { XmlElement element = (XmlElement) node; if (element.HasAttribute("href") ){ XmlAttribute href = element.GetAttributeNode("href"); string target = href.Value; target = GetAbsoluteLink(target, url); if (target != null) { string newtarget = String.Format ("source-id:{0}:xhtml:{1}", SourceID, target); href.Value = newtarget; } } } nodeList = docToProcess.GetElementsByTagName("img"); foreach(XmlNode node in nodeList) { XmlElement element = (XmlElement) node; if (element.HasAttribute("src") ){ XmlAttribute href = element.GetAttributeNode("src"); string target = href.Value; target = GetAbsoluteLink(target, url); if (target != null) { string newtarget = String.Format ("source-id:{0}:xhtml:{1}", SourceID, target); href.Value = newtarget; } } } return docToProcess; } public override void PopulateIndex (IndexMaker index_maker) { PopulateIndexFromNodes (Tree.RootNode); } void PopulateIndexFromNodes (Node start) { /*var nodes = start.Nodes; if (nodes != null) { foreach (Node n in nodes) PopulateIndexFromNodes (n); }*/ } } }