//Reading navigation map starting from <navMap> node private static async Task <EpubNavigationMap> ReadNavigationMapAsync(XmlReader reader) { EpubNavigationMap result = new EpubNavigationMap(); bool mapFound = await reader.ReadToFollowingAsync("navMap", "http://www.daisy.org/z3986/2005/ncx/"); if (!mapFound) { throw new Exception("EPUB parsing error: navMap section not found in the .toc file."); } //reading till the </navMap> tag appearance while (await reader.ReadAsync() && !(reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "navMap")) { //We are looking for a top-level <navPoint> entries, considering that it could be any level of nesting: if ((reader.LocalName == "navPoint") && (reader.NodeType != XmlNodeType.EndElement)) { //We need to create a subreader space to limit the scope for each single navPoint XmlReader subReader = reader.ReadSubtree(); EpubNavigationPoint navigationPoint = await ReadNavigationPointAsync(subReader); //we reached the end of the top-level <navPoint> entry and it is time to add it to collection and to get rid of the sub-reader result.Add(navigationPoint); subReader.Dispose(); } } return(result); }
private static EpubNavigationPoint ReadNavigationPoint(XElement navigationPointNode) { EpubNavigationPoint result = new EpubNavigationPoint(); foreach (XAttribute navigationPointNodeAttribute in navigationPointNode.Attributes()) { string attributeValue = navigationPointNodeAttribute.Value; switch (navigationPointNodeAttribute.Name.LocalName.ToLowerInvariant()) { case "id": result.Id = attributeValue; break; case "class": result.Class = attributeValue; break; case "playOrder": result.PlayOrder = attributeValue; break; } } if (String.IsNullOrWhiteSpace(result.Id)) { throw new Exception("Incorrect EPUB navigation point: point ID is missing."); } result.NavigationLabels = new List <EpubNavigationLabel>(); result.ChildNavigationPoints = new List <EpubNavigationPoint>(); foreach (XElement navigationPointChildNode in navigationPointNode.Elements()) { switch (navigationPointChildNode.Name.LocalName.ToLowerInvariant()) { case "navlabel": EpubNavigationLabel navigationLabel = ReadNavigationLabel(navigationPointChildNode); result.NavigationLabels.Add(navigationLabel); break; case "content": EpubNavigationContent content = ReadNavigationContent(navigationPointChildNode); result.Content = content; break; case "navpoint": EpubNavigationPoint childNavigationPoint = ReadNavigationPoint(navigationPointChildNode); result.ChildNavigationPoints.Add(childNavigationPoint); break; } } if (!result.NavigationLabels.Any()) { throw new Exception(String.Format("EPUB parsing error: navigation point {0} should contain at least one navigation label.", result.Id)); } if (result.Content == null) { throw new Exception(String.Format("EPUB parsing error: navigation point {0} should contain content.", result.Id)); } return(result); }
private static EpubNavigationMap ReadNavigationMap(XElement navigationMapNode) { EpubNavigationMap result = new EpubNavigationMap(); foreach (XElement navigationPointNode in navigationMapNode.Elements()) { if (String.Compare(navigationPointNode.Name.LocalName, "navPoint", StringComparison.OrdinalIgnoreCase) == 0) { EpubNavigationPoint navigationPoint = ReadNavigationPoint(navigationPointNode); result.Add(navigationPoint); } } return(result); }
private static async Task <EpubNavigationPoint> ReadNavigationPointAsync(XmlReader reader) { EpubNavigationPoint result = new EpubNavigationPoint(); //we have to skip first entry as it could be empty after new sub-reader created if (reader.NodeType == XmlNodeType.None) { await reader.ReadAsync(); } //Now the pointer should point to the <navPoint> itself while (reader.MoveToNextAttribute()) //Doing this we just passing through <navPoint> tag { switch (reader.LocalName.ToLowerInvariant()) //We have to collect all possible attributes from the <navPoint> { case "id": result.Id = reader.Value; break; case "class": result.Class = reader.Value; break; case "playorder": result.PlayOrder = reader.Value; break; } } if (String.IsNullOrWhiteSpace(result.Id)) { throw new Exception("Incorrect EPUB navigation point: point ID is missing"); } result.NavigationLabels = new List <EpubNavigationLabel>(); result.ChildNavigationPoints = new List <EpubNavigationPoint>(); // We need to make sure that we will return pointer back to <navPoint> entry after reading all attributes reader.MoveToElement(); //Now we are looking for subnodes - navLabel, content and sub-navPoints while (await reader.ReadAsync()) { if (reader.NodeType != XmlNodeType.EndElement) { switch (reader.LocalName.ToLowerInvariant()) { case "navlabel": EpubNavigationLabel navigationLabel = await ReadNavigationLabelAsync(reader); // Adding label to collection result.NavigationLabels.Add(navigationLabel); break; case "content": EpubNavigationContent content = await ReadNavigationContentAsync(reader); //Adding content to collection result.Content = content; break; case "navpoint": //Yeep. Looks like we found a <navPoint> sub-node XmlReader subTree = reader.ReadSubtree(); //Cooking a separate sub-reader scope for this node to separate it from the others siblings EpubNavigationPoint childNavigationPoint = await ReadNavigationPointAsync(subTree); // I hate recursion... //Adding a child to a collection result.ChildNavigationPoints.Add(childNavigationPoint); subTree.Dispose(); break; } } } ; return(result); }