Example #1
0
        /// <summary>
        /// Switches to the fragment algorithm with the specified context element.
        /// </summary>
        /// <param name="context">The context element where the algorithm is applied to.</param>
        public void SwitchToFragment(Node context)
        {
            if (started)
                throw new InvalidOperationException("Fragment mode has to be activated before running the parser!");

            switch (context.NodeName)
            {
                case HTMLTitleElement.Tag:
                case HTMLTextAreaElement.Tag:
                {
                    tokenizer.Switch(HtmlParseMode.RCData);
                    break;
                }
                case HTMLStyleElement.Tag:
                case HTMLSemanticElement.XmpTag:
                case HTMLIFrameElement.Tag:
                case HTMLNoElement.NoEmbedTag:
                case HTMLNoElement.NoFramesTag:
                {
                    tokenizer.Switch(HtmlParseMode.Rawtext);
                    break;
                }
                case HTMLScriptElement.Tag:
                {
                    tokenizer.Switch(HtmlParseMode.Script);
                    break;
                }
                case HTMLNoElement.NoScriptTag:
                {
                    if (doc.IsScripting)
                        tokenizer.Switch(HtmlParseMode.Rawtext);

                    break;
                }
                case HTMLSemanticElement.PlaintextTag:
                {
                    tokenizer.Switch(HtmlParseMode.Plaintext);
                    break;
                }
            }

            var root = new HTMLHtmlElement();
            doc.AppendChild(root);
            open.Add(root);
            Reset(context);

            fragmentContext = context;
            tokenizer.AcceptsCharacterData = !AdjustedCurrentNode.IsInHtml;

            do
            {
                if (context is HTMLFormElement)
                {
                    form = (HTMLFormElement)context;
                    break;
                }

                context = context.ParentNode;
            }
            while (context != null);
        }
Example #2
0
        /// <summary>
        /// See 8.2.5.4.9 The "in table" insertion mode.
        /// </summary>
        /// <param name="token">The passed token.</param>
        void InTable(HtmlToken token)
        {
            if (token.Type == HtmlTokenType.Comment)
            {
                AddComment(CurrentNode, token);
            }
            else if (token.Type == HtmlTokenType.DOCTYPE)
            {
                RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
            }
            else if (token.Type == HtmlTokenType.StartTag)
            {
                var tag = (HtmlTagToken)token;

                switch (tag.Name)
                {
                    case HTMLTableCaptionElement.Tag:
                    {
                        ClearStackBackToTable();
                        InsertScopeMarker();
                        var element = new HTMLTableCaptionElement();
                        AddElementToCurrentNode(element, token);
                        insert = HtmlTreeMode.InCaption;
                        break;
                    }
                    case HTMLTableColElement.ColgroupTag:
                    {
                        ClearStackBackToTable();
                        var element = new HTMLTableColElement();
                        AddElementToCurrentNode(element, token);
                        insert = HtmlTreeMode.InColumnGroup;
                        break;
                    }
                    case HTMLTableColElement.ColTag:
                    {
                        InTable(HtmlToken.OpenTag(HTMLTableColElement.ColgroupTag));
                        InColumnGroup(token);
                        break;
                    }
                    case HTMLTableSectionElement.BodyTag:
                    case HTMLTableSectionElement.HeadTag:
                    case HTMLTableSectionElement.FootTag:
                    {
                        ClearStackBackToTable();
                        var element = new HTMLTableSectionElement();
                        AddElementToCurrentNode(element, token);
                        insert = HtmlTreeMode.InTableBody;
                        break;
                    }
                    case HTMLTableCellElement.NormalTag:
                    case HTMLTableCellElement.HeadTag:
                    case HTMLTableRowElement.Tag:
                    {
                        InTable(HtmlToken.OpenTag(HTMLTableSectionElement.BodyTag));
                        InTableBody(token);
                        break;
                    }
                    case HTMLTableElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.TableNesting);

                        if (InTableEndTagTable())
                            Consume(token);

                        break;
                    }
                    case HTMLScriptElement.Tag:
                    case HTMLStyleElement.Tag:
                    {
                        InHead(token);
                        break;
                    }
                    case HTMLInputElement.Tag:
                    {
                        if (tag.GetAttribute("type").Equals("hidden", StringComparison.OrdinalIgnoreCase))
                        {
                            RaiseErrorOccurred(ErrorCode.InputUnexpected);
                            var element = new HTMLInputElement();
                            AddElementToCurrentNode(element, token, true);
                            CloseCurrentNode();
                        }
                        else
                        {
                            RaiseErrorOccurred(ErrorCode.TokenNotPossible);
                            InBodyWithFoster(token);
                        }

                        break;
                    }
                    case HTMLFormElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.FormInappropriate);

                        if (form == null)
                        {
                            var element = new HTMLFormElement();
                            AddElementToCurrentNode(element, token);
                            form = element;
                            CloseCurrentNode();
                        }

                        break;
                    }
                    default:
                    {
                        RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected);
                        InBodyWithFoster(token);
                        break;
                    }
                }
            }
            else if (token.Type == HtmlTokenType.EndTag)
            {
                var tag = (HtmlTagToken)token;

                switch (tag.Name)
                {
                    case HTMLTableElement.Tag:
                    {
                        InTableEndTagTable();
                        break;
                    }
                    case HTMLBodyElement.Tag:
                    case HTMLTableColElement.ColgroupTag:
                    case HTMLTableColElement.ColTag:
                    case HTMLTableCaptionElement.Tag:
                    case HTMLHtmlElement.Tag:
                    case HTMLTableSectionElement.BodyTag:
                    case HTMLTableRowElement.Tag:
                    case HTMLTableSectionElement.HeadTag:
                    case HTMLTableCellElement.HeadTag:
                    case HTMLTableSectionElement.FootTag:
                    case HTMLTableCellElement.NormalTag:
                    {
                        RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
                        break;
                    }
                    default:
                    {
                        RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected);
                        InBodyWithFoster(token);
                        break;
                    }
                }
            }
            else if (token.Type == HtmlTokenType.Character && CurrentNode != null && CurrentNode.IsTableElement())
            {
                InTableText((HtmlCharacterToken)token);
            }
            else if (token.Type == HtmlTokenType.EOF)
            {
                if (CurrentNode != doc.DocumentElement)
                    RaiseErrorOccurred(ErrorCode.CurrentNodeIsNotRoot);

                End();
            }
            else
            {
                RaiseErrorOccurred(ErrorCode.TokenNotPossible);
                InBodyWithFoster(token);
            }
        }
Example #3
0
        /// <summary>
        /// See 8.2.5.4.7 The "in body" insertion mode.
        /// </summary>
        /// <param name="token">The passed token.</param>
        void InBody(HtmlToken token)
        {
            if (token.Type == HtmlTokenType.Character)
            {
                var chrs = (HtmlCharacterToken)token;
                ReconstructFormatting();
                InsertCharacters(chrs.Data);

                if(chrs.HasContent)
                    frameset = false;
            }
            else if (token.Type == HtmlTokenType.Comment)
                AddComment(CurrentNode, token);
            else if (token.Type == HtmlTokenType.DOCTYPE)
                RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
            else if (token.Type == HtmlTokenType.StartTag)
            {
                var tag = (HtmlTagToken)token;

                switch (tag.Name)
                {
                    case HTMLHtmlElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.HtmlTagMisplaced);
                        AppendAttributes(tag, open[0]);
                        break;
                    }
                    case HTMLBaseElement.Tag:
                    case HTMLBaseFontElement.Tag:
                    case HTMLBgsoundElement.Tag:
                    case HTMLLinkElement.Tag:
                    case HTMLMenuItemElement.Tag:
                    case HTMLMetaElement.Tag:
                    case HTMLNoElement.NoFramesTag:
                    case HTMLScriptElement.Tag:
                    case HTMLStyleElement.Tag:
                    case HTMLTitleElement.Tag:
                    {
                        InHead(token);
                        break;
                    }
                    case HTMLBodyElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.BodyTagMisplaced);

                        if (open.Count > 1 && open[1] is HTMLBodyElement)
                        {
                            frameset = false;
                            AppendAttributes(tag, open[1]);
                        }

                        break;
                    }
                    case HTMLFrameSetElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.FramesetMisplaced);

                        if (open.Count != 1 && open[1] is HTMLBodyElement && frameset)
                        {
                            open[1].ParentNode.RemoveChild(open[1]);

                            while (open.Count > 1)
                                CloseCurrentNode();

                            var element = new HTMLFrameSetElement();
                            AddElementToCurrentNode(element, token);
                            insert = HtmlTreeMode.InFrameset;
                        }

                        break;
                    }
                    case HTMLSemanticElement.AddressTag:
                    case HTMLSemanticElement.ArticleTag:
                    case HTMLSemanticElement.AsideTag:
                    case HTMLQuoteElement.BlockTag:
                    case HTMLSemanticElement.CenterTag:
                    case HTMLDetailsElement.Tag:
                    case HTMLDialogElement.Tag:
                    case HTMLDirectoryElement.Tag:
                    case HTMLDivElement.Tag:
                    case HTMLDListElement.Tag:
                    case HTMLFieldSetElement.Tag:
                    case HTMLSemanticElement.FigcaptionTag:
                    case HTMLSemanticElement.FigureTag:
                    case HTMLSemanticElement.FooterTag:
                    case HTMLSemanticElement.HeaderTag:
                    case HTMLSemanticElement.HgroupTag:
                    case HTMLMenuElement.Tag:
                    case HTMLSemanticElement.NavTag:
                    case HTMLOListElement.Tag:
                    case HTMLParagraphElement.Tag:
                    case HTMLSemanticElement.SectionTag:
                    case HTMLSemanticElement.SummaryTag:
                    case HTMLUListElement.Tag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token);
                        break;
                    }
                    case HTMLHeadingElement.ChapterTag:
                    case HTMLHeadingElement.SubSubSubSubSectionTag:
                    case HTMLHeadingElement.SubSubSubSectionTag:
                    case HTMLHeadingElement.SubSubSectionTag:
                    case HTMLHeadingElement.SubSectionTag:
                    case HTMLHeadingElement.SectionTag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        if (CurrentNode is HTMLHeadingElement)
                        {
                            RaiseErrorOccurred(ErrorCode.HeadingNested);
                            CloseCurrentNode();
                        }

                        var element = new HTMLHeadingElement();
                        AddElementToCurrentNode(element, token);
                        break;
                    }
                    case HTMLPreElement.Tag:
                    case HTMLSemanticElement.ListingTag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        var element = new HTMLPreElement();
                        AddElementToCurrentNode(element, token);
                        frameset = false;
                        PreventNewLine();
                        break;
                    }
                    case HTMLFormElement.Tag:
                    {
                        if (form == null)
                        {
                            if (IsInButtonScope(HTMLParagraphElement.Tag))
                                InBodyEndTagParagraph();

                            var element = new HTMLFormElement();
                            AddElementToCurrentNode(element, token);
                            form = element;
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.FormAlreadyOpen);

                        break;
                    }
                    case HTMLLIElement.ItemTag:
                    {
                        InBodyStartTagListItem(tag);
                        break;
                    }
                    case HTMLLIElement.DefinitionTag:
                    case HTMLLIElement.DescriptionTag:
                    {
                        InBodyStartTagDefinitionItem(tag);
                        break;
                    }
                    case HTMLSemanticElement.PlaintextTag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        var plaintext = new HTMLElement();
                        AddElementToCurrentNode(plaintext, token);
                        tokenizer.Switch(HtmlParseMode.Plaintext);
                        break;
                    }
                    case HTMLButtonElement.Tag:
                    {
                        if (IsInScope(tag.Name))
                        {
                            RaiseErrorOccurred(ErrorCode.ButtonInScope);
                            InBodyEndTagBlock(tag.Name);
                            InBody(token);
                        }
                        else
                        {
                            ReconstructFormatting();
                            var element = new HTMLButtonElement();
                            AddElementToCurrentNode(element, token);
                            frameset = false;
                        }
                        break;
                    }
                    case HTMLAnchorElement.Tag:
                    {
                        for (var i = formatting.Count - 1; i >= 0; i--)
                        {
                            if (formatting[i] is ScopeMarkerNode)
                                break;
                            else if (formatting[i].NodeName == HTMLAnchorElement.Tag)
                            {
                                var format = formatting[i];
                                RaiseErrorOccurred(ErrorCode.AnchorNested);
                                HeisenbergAlgorithm(HtmlToken.CloseTag(HTMLAnchorElement.Tag));
                                if(open.Contains(format)) open.Remove(format);
                                if(formatting.Contains(format)) formatting.RemoveAt(i);
                                break;
                            }
                        }

                        ReconstructFormatting();
                        var element = new HTMLAnchorElement();
                        AddElementToCurrentNode(element, token);
                        AddFormattingElement(element);
                        break;
                    }
                    case HTMLFormattingElement.BTag:
                    case HTMLFormattingElement.BigTag:
                    case HTMLFormattingElement.CodeTag:
                    case HTMLFormattingElement.EmTag:
                    case HTMLFontElement.Tag:
                    case HTMLFormattingElement.ITag:
                    case HTMLFormattingElement.STag:
                    case HTMLFormattingElement.SmallTag:
                    case HTMLFormattingElement.StrikeTag:
                    case HTMLFormattingElement.StrongTag:
                    case HTMLFormattingElement.TtTag:
                    case HTMLFormattingElement.UTag:
                    {
                        ReconstructFormatting();
                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token);
                        AddFormattingElement(element);
                        break;
                    }
                    case HTMLFormattingElement.NobrTag:
                    {
                        ReconstructFormatting();

                        if (IsInScope(HTMLFormattingElement.NobrTag))
                        {
                            RaiseErrorOccurred(ErrorCode.NobrInScope);
                            HeisenbergAlgorithm(tag);
                            ReconstructFormatting();
                        }

                        var element = new HTMLElement();
                        AddElementToCurrentNode(element, token);
                        AddFormattingElement(element);
                        break;
                    }
                    case HTMLAppletElement.Tag:
                    case HTMLMarqueeElement.Tag:
                    case HTMLObjectElement.Tag:
                    {
                        ReconstructFormatting();
                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token);
                        InsertScopeMarker();
                        frameset = false;
                        break;
                    }
                    case HTMLTableElement.Tag:
                    {
                        if (doc.QuirksMode == QuirksMode.Off && IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        var element = new HTMLTableElement();
                        AddElementToCurrentNode(element, token);
                        frameset = false;
                        insert = HtmlTreeMode.InTable;
                        break;
                    }
                    case HTMLAreaElement.Tag:
                    case HTMLBRElement.Tag:
                    case HTMLEmbedElement.Tag:
                    case HTMLImageElement.Tag:
                    case HTMLKeygenElement.Tag:
                    case HTMLWbrElement.Tag:
                    {
                        InBodyStartTagBreakrow(tag);
                        break;
                    }
                    case HTMLInputElement.Tag:
                    {
                        ReconstructFormatting();
                        var element = new HTMLInputElement();
                        AddElementToCurrentNode(element, token, true);
                        CloseCurrentNode();

                        if (!tag.GetAttribute("type").Equals("hidden", StringComparison.OrdinalIgnoreCase))
                            frameset = false;
                        break;
                    }
                    case HTMLParamElement.Tag:
                    case HTMLSourceElement.Tag:
                    case HTMLTrackElement.Tag:
                    {
                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token, true);
                        CloseCurrentNode();
                        break;
                    }
                    case HTMLHRElement.Tag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        var element = new HTMLHRElement();
                        AddElementToCurrentNode(element, token, true);
                        CloseCurrentNode();
                        frameset = false;
                        break;
                    }
                    case HTMLImageElement.FalseTag:
                    {
                        RaiseErrorOccurred(ErrorCode.ImageTagNamedWrong);
                        tag.Name = HTMLImageElement.Tag;
                        goto case HTMLImageElement.Tag;
                    }
                    case HTMLIsIndexElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.TagInappropriate);

                        if (form == null)
                        {
                            InBody(HtmlToken.OpenTag(HTMLFormElement.Tag));

                            if (tag.GetAttribute("action") != String.Empty)
                                form.SetAttribute("action", tag.GetAttribute("action"));

                            InBody(HtmlToken.OpenTag(HTMLHRElement.Tag));
                            InBody(HtmlToken.OpenTag(HTMLLabelElement.Tag));

                            if (tag.GetAttribute("prompt") != String.Empty)
                                InsertCharacters(tag.GetAttribute("prompt"));
                            else
                                InsertCharacters("This is a searchable index. Enter search keywords:");

                            var input = HtmlToken.OpenTag(HTMLInputElement.Tag);
                            input.AddAttribute("name", HTMLIsIndexElement.Tag);

                            for (int i = 0; i < tag.Attributes.Count; i++)
                            {
                                if (tag.Attributes[i].Key == "name" || tag.Attributes[i].Key == "action" || tag.Attributes[i].Key == "prompt")
                                    continue;

                                input.AddAttribute(tag.Attributes[i].Key, tag.Attributes[i].Value);
                            }

                            InBody(input);
                            InBody(HtmlToken.CloseTag(HTMLLabelElement.Tag));
                            InBody(HtmlToken.OpenTag(HTMLHRElement.Tag));
                            InBody(HtmlToken.CloseTag(HTMLFormElement.Tag));
                        }
                        break;
                    }
                    case HTMLTextAreaElement.Tag:
                    {
                        var element = new HTMLTextAreaElement();
                        AddElementToCurrentNode(element, token);
                        tokenizer.Switch(HtmlParseMode.RCData);
                        originalInsert = insert;
                        frameset = false;
                        insert = HtmlTreeMode.Text;
                        PreventNewLine();
                        break;
                    }
                    case HTMLSemanticElement.XmpTag:
                    {
                        if (IsInButtonScope(HTMLParagraphElement.Tag))
                            InBodyEndTagParagraph();

                        ReconstructFormatting();
                        frameset = false;
                        RawtextAlgorithm(tag);
                        break;
                    }
                    case HTMLIFrameElement.Tag:
                    {
                        frameset = false;
                        RawtextAlgorithm(tag);
                        break;
                    }
                    case HTMLSelectElement.Tag:
                    {
                        ReconstructFormatting();
                        var element = new HTMLSelectElement();
                        AddElementToCurrentNode(element, token);
                        frameset = false;

                        switch (insert)
                        {
                            case HtmlTreeMode.InTable:
                            case HtmlTreeMode.InCaption:
                            case HtmlTreeMode.InRow:
                            case HtmlTreeMode.InCell:
                                insert = HtmlTreeMode.InSelectInTable;
                                break;

                            default:
                                insert = HtmlTreeMode.InSelect;
                                break;
                        }
                        break;
                    }
                    case HTMLOptGroupElement.Tag:
                    case HTMLOptionElement.Tag:
                    {
                        if (CurrentNode.NodeName == HTMLOptionElement.Tag)
                            InBodyEndTagAnythingElse(HtmlToken.CloseTag(HTMLOptionElement.Tag));

                        ReconstructFormatting();
                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token);
                        break;
                    }
                    case "rp":
                    case "rt":
                    {
                        if (IsInScope("ruby"))
                        {
                            GenerateImpliedEndTags();

                            if (CurrentNode.NodeName != "ruby")
                                RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
                        }

                        var element = HTMLElement.Factory(tag.Name);
                        AddElementToCurrentNode(element, token);
                        break;
                    }
                    case HTMLNoElement.NoEmbedTag:
                    {
                        RawtextAlgorithm(tag);
                        break;
                    }
                    case HTMLNoElement.NoScriptTag:
                    {
                        if (!doc.IsScripting)
                            goto default;

                        RawtextAlgorithm(tag);
                        break;
                    }
                    case MathMLElement.RootTag:
                    {
                        var element = new MathMLElement();
                        element.NodeName = tag.Name;
                        ReconstructFormatting();

                        for (int i = 0; i < tag.Attributes.Count; i++)
                        {
                            var name = tag.Attributes[i].Key;
                            var value = tag.Attributes[i].Value;
                            element.SetAttribute(ForeignHelpers.AdjustAttributeName(MathMLHelpers.AdjustAttributeName(name)), value);
                        }

                        CurrentNode.AppendChild(element);

                        if (!tag.IsSelfClosing)
                            open.Add(element);
                        break;
                    }
                    case SVGElement.RootTag:
                    {
                        var element = new SVGElement();
                        element.NodeName = tag.Name;
                        ReconstructFormatting();

                        for (int i = 0; i < tag.Attributes.Count; i++)
                        {
                            var name = tag.Attributes[i].Key;
                            var value = tag.Attributes[i].Value;
                            element.SetAttribute(ForeignHelpers.AdjustAttributeName(MathMLHelpers.AdjustAttributeName(name)), value);
                        }

                        CurrentNode.AppendChild(element);

                        if (!tag.IsSelfClosing)
                        {
                            open.Add(element);
                            tokenizer.AcceptsCharacterData = true;
                        }
                        break;
                    }
                    case HTMLTableCaptionElement.Tag:
                    case HTMLTableColElement.ColTag:
                    case HTMLTableColElement.ColgroupTag:
                    case HTMLFrameElement.Tag:
                    case HTMLHeadElement.Tag:
                    case HTMLTableSectionElement.BodyTag:
                    case HTMLTableCellElement.NormalTag:
                    case HTMLTableSectionElement.FootTag:
                    case HTMLTableCellElement.HeadTag:
                    case HTMLTableSectionElement.HeadTag:
                    case HTMLTableRowElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.TagCannotStartHere);
                        break;
                    }
                    default:
                    {
                        ReconstructFormatting();
                        var element = new HTMLUnknownElement();
                        AddElementToCurrentNode(element, token);
                        break;
                    }
                }
            }
            else if (token.Type == HtmlTokenType.EndTag)
            {
                var tag = (HtmlTagToken)token;

                switch (tag.Name)
                {
                    case HTMLBodyElement.Tag:
                    {
                        InBodyEndTagBody();
                        break;
                    }
                    case HTMLHtmlElement.Tag:
                    {
                        if (InBodyEndTagBody())
                            AfterBody(token);

                        break;
                    }
                    case HTMLSemanticElement.AddressTag:
                    case HTMLSemanticElement.ArticleTag:
                    case HTMLSemanticElement.AsideTag:
                    case HTMLQuoteElement.BlockTag:
                    case HTMLButtonElement.Tag:
                    case HTMLSemanticElement.CenterTag:
                    case HTMLDetailsElement.Tag:
                    case HTMLDialogElement.Tag:
                    case HTMLDirectoryElement.Tag:
                    case HTMLDivElement.Tag:
                    case HTMLDListElement.Tag:
                    case HTMLFieldSetElement.Tag:
                    case HTMLSemanticElement.FigcaptionTag:
                    case HTMLSemanticElement.FigureTag:
                    case HTMLSemanticElement.FooterTag:
                    case HTMLSemanticElement.HeaderTag:
                    case HTMLSemanticElement.HgroupTag:
                    case HTMLSemanticElement.ListingTag:
                    case HTMLSemanticElement.MainTag:
                    case HTMLMenuElement.Tag:
                    case HTMLSemanticElement.NavTag:
                    case HTMLOListElement.Tag:
                    case HTMLPreElement.Tag:
                    case HTMLSemanticElement.SectionTag:
                    case HTMLSemanticElement.SummaryTag:
                    case HTMLUListElement.Tag:
                    {
                        InBodyEndTagBlock(tag.Name);
                        break;
                    }
                    case HTMLFormElement.Tag:
                    {
                        var node = form;
                        form = null;

                        if (node != null && IsInScope(node.NodeName))
                        {
                            GenerateImpliedEndTags();

                            if (CurrentNode != node)
                                RaiseErrorOccurred(ErrorCode.FormClosedWrong);

                            open.Remove(node);
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.FormNotInScope);

                        break;
                    }
                    case HTMLParagraphElement.Tag:
                    {
                        InBodyEndTagParagraph();
                        break;
                    }
                    case HTMLLIElement.ItemTag:
                    {
                        if (IsInListItemScope(tag.Name))
                        {
                            GenerateImpliedEndTagsExceptFor(tag.Name);

                            if (CurrentNode.NodeName != tag.Name)
                                RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);

                            ClearStackBackTo(tag.Name);
                            CloseCurrentNode();
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.ListItemNotInScope);

                        break;
                    }
                    case HTMLLIElement.DefinitionTag:
                    case HTMLLIElement.DescriptionTag:
                    {
                        if (IsInScope(tag.Name))
                        {
                            GenerateImpliedEndTagsExceptFor(tag.Name);

                            if (CurrentNode.NodeName != tag.Name)
                                RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);

                            ClearStackBackTo(tag.Name);
                            CloseCurrentNode();
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.ListItemNotInScope);

                        break;
                    }
                    case HTMLHeadingElement.ChapterTag:
                    case HTMLHeadingElement.SubSubSubSubSectionTag:
                    case HTMLHeadingElement.SubSubSubSectionTag:
                    case HTMLHeadingElement.SubSubSectionTag:
                    case HTMLHeadingElement.SubSectionTag:
                    case HTMLHeadingElement.SectionTag:
                    {
                        if (IsHeadingInScope())
                        {
                            GenerateImpliedEndTags();

                            if (CurrentNode.NodeName != tag.Name)
                                RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);

                            ClearStackBackToHeading();
                            CloseCurrentNode();
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.HeadingNotInScope);

                        break;
                    }
                    case HTMLAnchorElement.Tag:
                    case HTMLFormattingElement.BTag:
                    case HTMLFormattingElement.BigTag:
                    case HTMLFormattingElement.CodeTag:
                    case HTMLFormattingElement.EmTag:
                    case HTMLFontElement.Tag:
                    case HTMLFormattingElement.ITag:
                    case HTMLFormattingElement.NobrTag:
                    case HTMLFormattingElement.STag:
                    case HTMLFormattingElement.SmallTag:
                    case HTMLFormattingElement.StrikeTag:
                    case HTMLFormattingElement.StrongTag:
                    case HTMLFormattingElement.TtTag:
                    case HTMLFormattingElement.UTag:
                    {
                        HeisenbergAlgorithm(tag);
                        break;
                    }
                    case HTMLAppletElement.Tag:
                    case HTMLMarqueeElement.Tag:
                    case HTMLObjectElement.Tag:
                    {
                        if (IsInScope(tag.Name))
                        {
                            GenerateImpliedEndTags();

                            if (CurrentNode.NodeName != tag.Name)
                                RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);

                            ClearStackBackTo(tag.Name);
                            CloseCurrentNode();
                            ClearFormattingElements();
                        }
                        else
                            RaiseErrorOccurred(ErrorCode.ObjectNotInScope);

                        break;
                    }
                    case HTMLBRElement.Tag:
                    {
                        RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
                        InBodyStartTagBreakrow(HtmlToken.OpenTag(HTMLBRElement.Tag));
                        break;
                    }
                    default:
                    {
                        InBodyEndTagAnythingElse(tag);
                        break;
                    }
                }
            }
            else if (token.Type == HtmlTokenType.EOF)
            {
                for (var i = 0; i < open.Count; i++)
                {
                    switch (open[i].NodeName)
                    {
                        case HTMLLIElement.DescriptionTag:
                        case HTMLLIElement.DefinitionTag:
                        case HTMLLIElement.ItemTag:
                        case HTMLParagraphElement.Tag:
                        case HTMLTableSectionElement.BodyTag:
                        case HTMLTableCellElement.HeadTag:
                        case HTMLTableSectionElement.FootTag:
                        case HTMLTableCellElement.NormalTag:
                        case HTMLTableSectionElement.HeadTag:
                        case HTMLTableRowElement.Tag:
                        case HTMLBodyElement.Tag:
                        case HTMLHtmlElement.Tag:
                            break;

                        default:
                            RaiseErrorOccurred(ErrorCode.BodyClosedWrong);
                            i = open.Count;
                            break;
                    }
                }

                End();
            }
        }