예제 #1
0
        private void OnStartTagClose(object sender, HtmlParserCloseTagEventArgs e)
        {
            // e.Token contain Token with range for > or /> if well formed
            // or IsGhost is set to true otherwise

            Debug.Assert(_currentElementRecord != null);

            // Close start tag of the current element and push element
            // on the stack if element is not self-closing (or self-closed via />).

            ElementNode currentElement = _currentElementRecord.Element;
            ReadOnlyCollection <AttributeNode> attributes = AttributeNode.EmptyCollection;

            if (_currentElementRecord.StartTagAttributes.Count > 0)
            {
                attributes = new ReadOnlyCollection <AttributeNode>(_currentElementRecord.StartTagAttributes);
            }

            if (currentElement.StartTag.NameToken == null ||
                currentElement.Name.Equals("!doctype", StringComparison.OrdinalIgnoreCase))
            {
                currentElement.StartTag.Complete(attributes, e.CloseAngleBracket, e.IsClosed, e.IsShorthand, true);

                currentElement.CompleteElement(e.CloseAngleBracket, e.IsClosed,
                                               ElementNode.EmptyCollection,
                                               attributes,
                                               AttributeNode.EmptyCollection);
            }
            else
            {
                // Check if element is self-closing by calling URI info provider for a given namespace.
                bool selfClosing = false;

                NameToken nameToken = currentElement.StartTag.NameToken;
                if (nameToken != null)
                {
                    selfClosing = _tree.HtmlClosureProvider.IsSelfClosing(_tree.Text, nameToken.PrefixRange, nameToken.NameRange);
                }

                currentElement.StartTag.Complete(attributes, e.CloseAngleBracket, e.IsClosed, e.IsShorthand, selfClosing);

                currentElement.CompleteElement(e.CloseAngleBracket, e.IsClosed,
                                               ElementNode.EmptyCollection,
                                               attributes,
                                               AttributeNode.EmptyCollection);

                if (!selfClosing && !e.IsShorthand)
                {
                    _elementStack.Push(_currentElementRecord);
                }
            }

            _currentElementRecord = null;
        }
예제 #2
0
        private void OnEndTagClose(object sender, HtmlParserCloseTagEventArgs e)
        {
            if (_currentElementRecord != null)
            {
                ElementNode element = _currentElementRecord.Element;
                ReadOnlyCollection <ElementNode> children = ElementNode.EmptyCollection;
                if (_currentElementRecord.Children.Count > 0)
                {
                    children = new ReadOnlyCollection <ElementNode>(_currentElementRecord.Children);
                }

                ReadOnlyCollection <AttributeNode> startTagAttributes = AttributeNode.EmptyCollection;
                if (_currentElementRecord.StartTagAttributes.Count > 0)
                {
                    startTagAttributes = new ReadOnlyCollection <AttributeNode>(_currentElementRecord.StartTagAttributes);
                }

                ReadOnlyCollection <AttributeNode> endTagAttributes = AttributeNode.EmptyCollection;
                if (_currentElementRecord.EndTagAttributes.Count > 0)
                {
                    endTagAttributes = new ReadOnlyCollection <AttributeNode>(_currentElementRecord.EndTagAttributes);
                }

                element.EndTag.Complete(endTagAttributes, e.CloseAngleBracket, e.IsClosed, false, false);
                element.CompleteElement(e.CloseAngleBracket, true, children, startTagAttributes, endTagAttributes);

                _currentElementRecord = null;
            }

            CloseOrphanedEndTag(e.CloseAngleBracket, e.IsClosed);
        }
예제 #3
0
        private void OnParseEnd(object sender, HtmlParserRangeEventArgs e)
        {
            // Collect all orphaned end tags since they belong to the currently
            //
            CloseOrphanedEndTag(new TextRange(e.Range.End, 0), false);

            // Close all element that are still on the stack
            while (_elementStack.Count > 0)
            {
                ElementRecord elementRecord = _elementStack.Pop();

                ElementNode element = elementRecord.Element;
                ReadOnlyCollection <ElementNode> children = ElementNode.EmptyCollection;
                if (elementRecord.Children.Count > 0)
                {
                    children = new ReadOnlyCollection <ElementNode>(elementRecord.Children);
                }

                ReadOnlyCollection <AttributeNode> startTagAttributes = AttributeNode.EmptyCollection;
                if (elementRecord.StartTagAttributes.Count > 0)
                {
                    startTagAttributes = new ReadOnlyCollection <AttributeNode>(elementRecord.StartTagAttributes);
                }

                ReadOnlyCollection <AttributeNode> endTagAttributes = AttributeNode.EmptyCollection;
                if (elementRecord.EndTagAttributes.Count > 0)
                {
                    endTagAttributes = new ReadOnlyCollection <AttributeNode>(elementRecord.EndTagAttributes);
                }

                element.CompleteElement(TextRange.FromBounds(e.Range.End, e.Range.End), false, children, startTagAttributes, endTagAttributes);
            }

            _tree.RootNode  = _rootNodeRecord.Element as RootNode;
            _rootNodeRecord = null;

            _tree.CommentCollection.Sort();

            var parser = sender as HtmlParser;

            _tree.DocType = parser.DocType;

            TreeBuildingTime = DateTime.UtcNow - _startTime;
        }
예제 #4
0
        private ElementRecord CloseElements(ITextRange nameRange, int position, string[] containerNames)
        {
            ElementRecord last                         = null;
            int           count                        = 0;
            bool          foundSameElement             = false;
            bool          foundContainer               = false;
            bool          testImplicitClosureWalkingUp = (containerNames.Length > 0);
            bool          foundImplicitlyClosedElement = false;
            string        name                         = _tree.Text.GetText(nameRange);

            // Dev12 764293: Match end tags regardless of parsing mode, and let validation ensure the casing.
            // var comparison = Parser.ParsingMode == ParsingMode.Html ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
            var comparison = StringComparison.OrdinalIgnoreCase;

            // Walk up the stack looking for element name but stop at possible container
            // so we don't close outer <li> by inner <li> in <ol><li><ol><li> and rather
            // stop at the nearest <ol> which is a 'hard' container for <li>.

            foreach (var elementRecord in _elementStack)
            {
                ITextRange qualifiedNameRange = elementRecord.Element.QualifiedNameRange;
                string     qualifiedName      = _tree.Text.GetText(qualifiedNameRange);

                if (String.Compare(qualifiedName, name, comparison) == 0)
                {
                    foundSameElement = true;
                    count++; // Ensure we close the element with the same name
                    break;
                }

                foreach (var containerName in containerNames)
                {
                    if (String.Compare(qualifiedName, containerName, comparison) == 0)
                    {
                        foundContainer = true;
                        break;
                    }
                }

                if (foundContainer)
                {
                    break;
                }

                if (testImplicitClosureWalkingUp && !foundImplicitlyClosedElement)
                {
                    string[] containerNamesCurrentElement;
                    if (!String.IsNullOrEmpty(qualifiedName) && _tree.HtmlClosureProvider.IsImplicitlyClosed(_tree.Text, qualifiedNameRange, out containerNamesCurrentElement))
                    {
                        foundImplicitlyClosedElement = true;
                    }
                }

                count++;
            }

            if (foundSameElement || (foundImplicitlyClosedElement && foundContainer))
            {
                for (int i = 0; i < count; i++)
                {
                    last = _elementStack.Pop();
                    ElementNode element = last.Element;

                    ReadOnlyCollection <ElementNode> children = ElementNode.EmptyCollection;
                    if (last.Children.Count > 0)
                    {
                        children = new ReadOnlyCollection <ElementNode>(last.Children);
                    }

                    ReadOnlyCollection <AttributeNode> startTagAttributes = AttributeNode.EmptyCollection;
                    if (last.StartTagAttributes.Count > 0)
                    {
                        startTagAttributes = new ReadOnlyCollection <AttributeNode>(last.StartTagAttributes);
                    }

                    ReadOnlyCollection <AttributeNode> endTagAttributes = AttributeNode.EmptyCollection;
                    if (last.EndTagAttributes.Count > 0)
                    {
                        endTagAttributes = new ReadOnlyCollection <AttributeNode>(last.EndTagAttributes);
                    }

                    element.CompleteElement(TextRange.FromBounds(position, position), true, children, startTagAttributes, endTagAttributes);
                }
            }

            return(last);
        }