public static TableOfContents GetTableOfContents(this EBook eBook) { if (eBook.Spine == null) { eBook.Spine = eBook.GetSpine(); } var tocXml = File.ReadAllText(eBook.Manifest[eBook.Spine.Toc].ContentLocation); var doc = XDocument.Parse(tocXml); var ns = doc.Root.GetDefaultNamespace(); var ncxNode = doc.Element(ns + "ncx"); var tableOfContents = new TableOfContents { Title = ncxNode.Element(ns + "docTitle").Element(ns + "text").Value }; var navMapNode = ncxNode.Element(ns + "navMap"); IEnumerable <NavPoint> ParseNavPoints(XElement node, int level) { var navPoints = new List <NavPoint>(); var navPointNodes = node.Elements(ns + "navPoint").ToList(); foreach (var navPointNode in navPointNodes) { var filePath = navPointNode.Element(ns + "content").Attribute("src").Value; var pathBuilder = new StringBuilder(); foreach (var c in filePath) { if (c == '#' && pathBuilder.ToString().EndsWith(".html")) { break; } pathBuilder.Append(c); } var navPoint = new NavPoint { ContentPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(eBook.Manifest[eBook.Spine.Toc].ContentLocation), pathBuilder.ToString())), Id = navPointNode.Attribute("id")?.Value, Level = level, PlayOrder = int.Parse(navPointNode.Attribute("playOrder")?.Value), Text = navPointNode.Element(ns + "navLabel")?.Element(ns + "text")?.Value }; foreach (var subNavPoint in ParseNavPoints(navPointNode, level + 1).ToList()) { navPoint.Items.Add(subNavPoint); } navPoints.Add(navPoint); } return(navPoints); } foreach (var navPoint in ParseNavPoints(navMapNode, 0).ToList()) { tableOfContents.Items.Add(navPoint); } return(tableOfContents); }