public override IEnumerable<TokenBase> GetTokens()
 {
     var propertiesStack = new Stack<TextVisualProperties>();
     var item = new TextVisualProperties();
     propertiesStack.Push(item);
     var top = new TokenIndex();
     return _root.Elements(_ns + "body").SelectMany(b => ParseNodes(b, propertiesStack, top, 0, "2"));
 }
 protected IEnumerable<TokenBase> ParseText(string text, TokenIndex top)
 {
     foreach (string word in text.BreakToWords())
     {
         if (string.IsNullOrEmpty(word))
             yield return new WhitespaceToken(top.Index++);
         else
             yield return new TextToken(top.Index++, WebUtility.HtmlDecode(word));
     }
 }
        private IEnumerable<TokenBase> ParseNodes(XContainer container, Stack<TextVisualProperties> propertiesStack, TokenIndex top, int bookLevel, string pointer, int parentID = -1)
        {
            var pointerIndex = 0;
            foreach (XNode node in container.Nodes())
            {
                pointerIndex++;
                var text = node as XText;
                if (!string.IsNullOrEmpty(text?.Value))
                {
                    foreach (TokenBase token in ParseText(text.Value, top))
                    {
                        yield return token;
                    }
                }
                var element = node as XElement;
                if(element == null)
                    continue;

                TextVisualProperties properties = propertiesStack.Peek().Clone().Update(element, _styleSheet);
                
                string localName = element.Name.LocalName;
                int level = bookLevel;

                if (localName == "a")
                {
                    ProcessLinks(properties, element);
                }
                ProcessAnchors(top, element);

                if (localName == "section")
                {
                    yield return new NewPageToken(top.Index++);
                    level++;
                }

                if (localName == "title")
                {
                    ProcessTitleData(top, element, level);
                }

                if (localName == "image")
                {
                    XAttribute hrefAttr = element.Attributes().FirstOrDefault(t => (t.Name.LocalName == "href"));
                    string href = ((hrefAttr != null) ? hrefAttr.Value : string.Empty).TrimStart('#');
                    var pictureToken = new PictureToken(top.Index++, href);
                    yield return pictureToken;
                }
                else
                {
                    var tagOpen = new TagOpenToken(top.Index++, element, properties, parentID, pointer + @"/" + pointerIndex);
                    yield return tagOpen;

                    propertiesStack.Push(properties);
                    foreach (TokenBase token in ParseNodes(element, propertiesStack, top, level, pointer+@"/"+pointerIndex, tagOpen.ID))
                    {
                        yield return token;
                    }
                    propertiesStack.Pop();

                    yield return new TagCloseToken(top.Index++, parentID);
                }
                
            }
        }
 private void ProcessTitleData(TokenIndex top, XElement xelement, int bookLevel)
 {
     var item = new BookChapter
                    {
                        Level = bookLevel,
                        Title = GetText(xelement),
                        TokenID = top.Index
                    };
     _chapters.Add(item);
 }
 private void ProcessAnchors(TokenIndex top, XElement xelement)
 {
     XAttribute attribute = xelement.Attributes().FirstOrDefault(t => (t.Name.LocalName == "id"));
     if (attribute != null)
     {
         _anchors[attribute.Value] = top.Index;
     }
 }