private static FrozenFragment CreateTextFragment(FrozenFragment parent, ref string c, IList <ManifestItem> data) { // if no text just proceed if (c.Length == 0) { return(parent); } // close open tags or open closed tags HtmlDocument nodeCheck = new HtmlDocument(); nodeCheck.OptionAutoCloseOnEnd = true; nodeCheck.OptionCheckSyntax = true; nodeCheck.OptionFixNestedTags = true; nodeCheck.LoadHtml(c); if (nodeCheck.ParseErrors.Count() > 0) { // handle parser errors } var f = new FrozenFragment { Name = "Paragraph", TypeOfFragment = FragmentType.Html, Parent = parent }; var body = nodeCheck.DocumentNode.SelectSingleNode("//body"); CreateEmbeddedImages(f, body, data); f.Content = UTF8Encoding.UTF8.GetBytes(body.InnerHtml); parent.Children.Add(f); c = String.Empty; return(f); }
/// <summary> /// Create the final HTML from a frozen fragment. There is no scaling or file handling as the frozen fragments are ready to go. /// </summary> /// <param name="fragment"></param> /// <param name="withNumbers"></param> /// <returns></returns> public string CreateFragmentHtml(FrozenFragment fragment, CreateImageHandler createImage, ScaleImageHandler scaleImage, bool withNumbers = true) { var flatFragments = fragment.Children.FlattenHierarchy() .Where(f => f.TypeOfFragment == FragmentType.Html) .ToList(); var sb = new StringBuilder(); sb.AppendLine(Encoding.UTF8.GetString(fragment.Content)); flatFragments.Select(f => sb.AppendLine(Encoding.UTF8.GetString(f.Content))); var fragmentContent = sb.ToString(); // assume children provide resources if (fragment.HasChildren()) { foreach (var resources in fragment.Children) { var imgRegex = new Regex(String.Format(@"src=""{0}""", resources.ItemHref)); if (!imgRegex.Match(fragmentContent).Success) { continue; } var newPath = createImage(this, new CreateImageArguments { FileName = resources.ItemHref }); fragmentContent = imgRegex.Replace(fragmentContent, String.Format(@"src=""{0}""", newPath)); } } return(fragmentContent); }
public void Convert(EpubBook book, Published p, PortalContext context) { Published = p; Context = context; // 1. The spine is used to create one single document as a source var spineIds = book.PackageData.Spine.ItemRefs.Select(i => i.IdRef).ToList(); // all elements var data = book.PackageData.Manifest.Items; // 2. Get the content elements only var content = data.Where(i => spineIds.Any(sid => sid == i.Identifier)).Select(i => i).ToList(); // fragments form a hierarchy, beginning with <h1> on the first level FrozenFragment rootFragment = new FrozenFragment { Name = book.PackageData.MetaData.Title.Text, ItemHref = "Opus (Import)", Published = p, TypeOfFragment = FragmentType.Meta, Children = new List <FrozenFragment>() }; switch (_method) { case Method.NcxToc: case Method.Html: // 3. Create source var complete = new StringBuilder(); complete.AppendLine("<body>"); foreach (var html in content) { complete.AppendFormat(@"<a name=""{0}"" ></a>", html.Identifier); complete.Append(GetBodyFromManifest(html.Data)); } complete.AppendLine("</body>"); // 5. HtmlDocument allHtml = new HtmlDocument(); allHtml.OptionAutoCloseOnEnd = true; allHtml.OptionFixNestedTags = true; allHtml.OptionOutputAsXml = true; allHtml.LoadHtml(complete.ToString()); var body = allHtml.DocumentNode.SelectSingleNode("//body"); switch (_method) { case Method.NcxToc: NcxParser(book, body, rootFragment); break; case Method.Html: var htmlConverter = new HtmlToFrozenFragments(); htmlConverter.Convert(body.InnerHtml, data); break; } break; case Method.Spine: SpineParser(content, rootFragment, data); break; } //Context.SaveChanges(); }
private string CreateDataFragment(FrozenFragment fragment) { // identify fragment // get attribute string content; switch (fragment.TypeOfFragment) { case FragmentType.Html: content = System.Text.Encoding.UTF8.GetString(fragment.Content); break; default: // TODO: Implement this throw new NotImplementedException(); } return(content); }
public FrozenFragment Convert(string html, IList <ManifestItem> resources) { var allHtml = new HtmlDocument { OptionAutoCloseOnEnd = true, OptionFixNestedTags = true, OptionOutputAsXml = true }; allHtml.LoadHtml(html); // fragments form a hierarchy, beginning with <h1> on the first level var rootFragment = new FrozenFragment { Name = "Root", ItemHref = "root", TypeOfFragment = FragmentType.Meta, Children = new List <FrozenFragment>(), Published = null }; var c = String.Empty; // current content for text snippet var body = allHtml.DocumentNode.SelectSingleNode("//body"); ElementParser(body.ChildNodes, rootFragment, resources); return(rootFragment); }
private static void SpineParser(EpubBook book, Published p) { var spineIds = book.PackageData.Spine.ItemRefs.Select(i => i.IdRef).ToList(); var data = book.PackageData.Manifest.Items; // 2. Get the content elements var content = data.Where(i => spineIds.Any(sid => sid == i.Identifier)).Select(i => new { Data = i.Data, Identifier = i.Href, Name = i.Identifier }); FrozenFragment rootFragment = new FrozenFragment { Name = "Root", TypeOfFragment = FragmentType.Meta, Children = new List <FrozenFragment>() }; int orderNr = 1; foreach (var file in content) { var c = UTF8Encoding.UTF8.GetString(file.Data); CreateTextFragment(rootFragment, ref c, data); } p.FrozenFragments = rootFragment.Children; }
private static void CreateEmbeddedImages(FrozenFragment parent, HtmlNode element, IList <ManifestItem> data) { if (element.SelectNodes(".//img") == null) { return; } foreach (var img in element.SelectNodes(".//img")) { var alt = img.Attributes["alt"] != null ? img.Attributes["alt"].Value : "Generic Image"; var cnt = data.FirstOrDefault(d => img.Attributes["src"].Value.EndsWith(d.Href)); var r = new FrozenFragment { Name = alt, Content = cnt.Data, TypeOfFragment = FragmentType.Image, ItemHref = Guid.NewGuid().ToString() }; if (parent.Children == null) { parent.Children = new List <FrozenFragment>(); } parent.Children.Add(r); img.Attributes["src"].Value = r.ItemHref; } }
private void ElementParser(IEnumerable <HtmlNode> elements, FrozenFragment rootFragment, IList <ManifestItem> data) { // loop through all first level children FrozenFragment activeFragment = rootFragment; string c = ""; foreach (var element in elements) { string e = element.Name.ToLower(); // Text elements are kept in a single fragment if they contain more than exactly one container if (textElements.Contains(e)) { if (element.HasChildNodes) { // if the only element is a container, keep the container and throw the element away if (element.ChildNodes.Count() == 1) { var subel = element.ChildNodes.Single(); var subname = element.ChildNodes.Single().Name.ToLower(); if (contElements.Contains(subname)) { CreateTextFragment(activeFragment, ref c, data); switch (subname) { case "table": Debug.WriteLine("inner table " + element.OuterHtml); CreateTableFragment(activeFragment, subel, data); break; case "img": Debug.WriteLine("inner image " + element.OuterHtml); CreateImageFragment(activeFragment, subel, data); break; } continue; } } } // collect element until we reach another container or header c += element.OuterHtml; } // if (headElements.Contains(e)) { // detect current header element int l = 0; // detect level where we already are int h = activeFragment.Level; // get where we need to be # pragma warning disable CS0462 if (e.StartsWith("h") && e.Length == 2 && Int32.TryParse(e.Substring(1), out l)) { ; } # pragma warning restore CS0462 l++; // zero based Debug.WriteLine("hx h:{0} l:{1}", h, l); // each section writes the current text CreateTextFragment(activeFragment, ref c, data); if (l == 1) { // first level activeFragment = CreateSectionFragment(activeFragment, element); h = 0; } else { if (l == h) { // same level = add to current parent activeFragment = CreateSectionFragment(activeFragment.Parent, element); } if (l > h) { // one level deeper = add to last current activeFragment = CreateSectionFragment(activeFragment, element); } if (l < h) { // one level higher = add again to former parent while (activeFragment.Parent != null && activeFragment.Level >= l) { activeFragment = activeFragment.Parent; } activeFragment = CreateSectionFragment(activeFragment, element); } } continue; }
/// <summary> /// The builder itself, creates the HTML from property data using reflection. /// </summary> /// <param name="snippet">The source snippet</param> /// <param name="numbering"> </param> /// <param name="targetFragment"></param> /// <returns>The final HTML string</returns> public string BuildHtml(Element snippet, IDictionary <string, NumberingSchema> numbering, FrozenFragment targetFragment) { if (String.IsNullOrEmpty(HtmlPattern)) { return(snippet.RawContent); } var t = snippet.WidgetName; if (numbering != null) { if (numbering.ContainsKey(t) && snippet is NumberedSnippet) { // set regular snippets ((NumberedSnippet)snippet).Divider = numbering[t].Divider; ((NumberedSnippet)snippet).Minor = numbering[t].Minor; ((NumberedSnippet)snippet).Label = numbering[t].Label; ((NumberedSnippet)snippet).Separator = numbering[t].Separator; ((NumberedSnippet)snippet).Major = numbering[t].Major; numbering[t].Minor = numbering[t].Minor + 1; } else { // special treatment for sections if (snippet is Section) { var d = snippet.Level - 1; var s = t + d; ((Section)snippet).SetCounterString(numbering[s].Separator); } } } // assign properties to the builder string var type = snippet.GetType(); var propVals = new object[Properties.Length]; for (var i = 0; i < propVals.Length; i++) { PropertyInfo prop = null; try { prop = type.GetProperty(Properties[i]); if (prop == null) { throw new ArgumentOutOfRangeException("Builder Attribute provided wrong properties for object of type " + type); } if (prop.GetIndexParameters().Length > 0) { propVals[i] = prop.GetValue(snippet, new object[] { Target, targetFragment }); } else { propVals[i] = prop.GetValue(snippet); } } catch (Exception ex) { Debug.WriteLine(ex.Message, prop == null ? propVals[i] : prop.Name); } } return(String.Format(HtmlPattern, propVals)); }
/// <summary> /// Create this Element as HTML and process down with all children. /// </summary> /// <param name="snippets">Create HTML for these snippets in distinct order, section resolve their children independently.</param> /// <param name="target">The current production target the builder is working for.</param> /// <param name="targetFragment"></param> /// <returns></returns> protected string CreateChildren(IEnumerable <Snippet> snippets, GroupKind target, FrozenFragment targetFragment) { Element opus = this; do { opus = opus.Parent; } while (!(opus is Opus)); var numbering = ((Opus)opus).Numbering; var flatContent = new StringBuilder(); Action <Snippet> convert = null; convert = e => { var builder = e.GetType().GetCustomAttributes(typeof(SnippetBuilderAttribute), true).OfType <SnippetBuilderAttribute>().First(sb => sb.Target == target); flatContent.Append(builder.BuildHtml(e, numbering, targetFragment)); }; snippets.OrderBy(s => s.OrderNr).ToList().ForEach(c => convert(c)); return(flatContent.ToString()); }
public abstract string this[GroupKind target, FrozenFragment targetFragment] { get; }