internal override bool IsValidNode(HtmlNode node)
        {
            if (node == null)
            {
                return false;
            }

            if (node.Parent == null)
            {
                return false;
            }

            bool isValid = false;

            foreach (HtmlNode child in node.GetParent().GetChildren())
            {
                if (child.Tag == HtmlTag.TEXT && child.Html.Trim() == string.Empty)
                {
                    continue;
                }

                //Find first child tag which matches the node's tag. The break statement will discard the loop after finding the first matching node.
                //If the node is the first child, it will apply the styles.
                isValid = string.Compare(node.Tag, child.Tag, StringComparison.InvariantCultureIgnoreCase) == 0 && node == child;

                //The loop only needs to check the first child element except the empty text element. So we can skip here.
                break;

            }

            return isValid;
        }
        private void InterpretStyles(HtmlNode htmlNode)
        {
            string style;

            if (!HtmlStyle.IsNonStyleElement(htmlNode.Tag))
            {
                if (htmlNode.Attributes.TryGetValue("style", out style))
                {
                    CSSParser cssParser = new CSSParser();
                    htmlNode.AddStyles(cssParser.ParseRules(style, SelectorType.Inline));
                }

                Parse(htmlNode);
            }

            foreach (HtmlNode node in htmlNode.GetChildren())
            {
                InterpretStyles(node);
            }

            //This loop only needs when the parent is null. If parent is not null, it will loop through all the 
            //child elements thus next nodes processed without this loop.
            if (htmlNode.Parent == null && htmlNode.Next != null)
            {
                InterpretStyles(htmlNode.GetNext());
            }
        }
        protected override bool ProcessHtml(int position, ref HtmlNode node)
        {
            bool tagCreated = false;
            IOpenTag openTag;
            ICloseTag closeTag;

            if (IsOpenTag(position, out openTag))
            {
                //+1 is required because the Html is zero based array so the position is always -1 of total length.
                tagCreated = CreateTag(HtmlTag.TEXT, startPosition, startPosition, position,
                    position, parent, out node);

                context.SetAnalyzer(openTag.GetAnalyzer(position, parent));
            }
            else if (IsCloseTag(position, out closeTag))
            {
                tagCreated = CreateTag(HtmlTag.TEXT, startPosition, startPosition, position,
                    position, parent, out node);

                closeTag.Init(position, parent);
                context.SetAnalyzer(closeTag.GetAnalyzer());
            }
            else if (position + 1 == context.EOF)//Reached EOF and still there are no tag created. 
            {                                    //So lets process if there is any pending text.
                tagCreated = CreateTag(HtmlTag.TEXT, startPosition, startPosition, position + 1,
                    position + 1, parent, out node);
            }

            return tagCreated;
        }
 internal override void ApplyStyle(HtmlNode node, List<HtmlStyle> htmlStyles)
 {
     if (IsValidNode(node))
     {
         node.CopyHtmlStyles(htmlStyles, CalculateSpecificity(SelectorType.Global));
     }
 }
        internal override bool IsValidNode(HtmlNode node)
        {
            if (node == null)
            {
                return false;
            }

            if (string.IsNullOrEmpty(currentSelector))
            {
                return false;
            }

            bool isValid = false;

            string className;

            if (node.Attributes.TryGetValue(key, out className))
            {
                string[] names = className.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string name in names)
                {
                    if (string.Compare(currentSelector, name, StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        isValid = true;
                    }
                }
            }

            return isValid;
        }
        internal override bool IsValidNode(HtmlNode node)
        {
            if (node == null)
            {
                return false;
            }

            if (string.IsNullOrEmpty(currentSelector))
            {
                return false;
            }

            bool isValid = false;
            string id;

            if (node.Attributes.TryGetValue(key, out id))
            {
                if (string.Compare(currentSelector, id, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    isValid = true;
                }
            }

            return isValid;
        }
        internal override void Parse(HtmlNode node, Specificity specificity, List<HtmlStyle> htmlStyles)
        {
            if (node.Next != null)
            {
            	HtmlNode temp = node.GetNext();

                //Empty text nodes can be avoid. This loop will skip those.
                while (temp != null && temp.Tag == HtmlTag.TEXT)
                {
                	temp = temp.GetNext();
                }

                if (temp != null)
                {
                    CSSelector nextSelector;
			
					if (context.ParseSelector(this.selectorText, out nextSelector))
					{
						if (nextSelector != null && nextSelector.IsValidNode(temp))
						{
                            nextSelector.AddSpecificity(specificity);
							nextSelector.Parse(temp, htmlStyles);
						}
					}
                }
            }
        }
        protected bool CreateTag(string tag, int htmlStart, int textStart, int textEnd, int htmlEnd,
            HtmlNode parent, out HtmlNode node)
        {
            node = null;

            if (htmlEnd != -1 && htmlEnd <= htmlStart)
            {
                return false;
            }

            if (textEnd != -1 && textEnd < textStart)
            {
                return false;
            }

            node = new HtmlNode(tag, htmlStart, textStart, textEnd, htmlEnd, context.HtmlContext, parent);

            if (context.PreviousNode != null)
            {
                node.SetPreviousNode(context.PreviousNode);
                context.PreviousNode.SetNextNode(node);
            }

            context.PreviousNode = node;

            return parent == null;
        }
        protected override bool ProcessHtml(int position, ref HtmlNode node)
        {
            if (!onTagExecuted)
            {
                onTagExecuted = true;
                TagCreated(HtmlTag.COMMENT);
            }

            bool tagCreated = false;
            bool isEnd = position + 3 <= context.EOF && context.Html.Substring(position, 3) == end;

            if (isEnd)
            {
                tagCreated = CreateTag(HtmlTag.COMMENT, startPosition, startPosition, position + 3,
                    position + 3, parent, out node);

                if (!AssignNextAnalyzer(position + 3, parent))
                {
                    context.SetAnalyzer(context.GetTextAnalyzer(position + 3, parent));
                }

                context.SetPosition(position + 3);
            }

            return tagCreated;
        }
		public override bool Traverse()
		{
			if (index >= eof)
			{
				current = null;
				return false;
			}

			bool canTraverse = false;

			while (index < eof)
			{
				canTraverse = analyzer.Process(index, ref current);

				++index;

				if (canTraverse)
				{
					break;
				}
			}

			canTraverse = FinilizeNodes(index, ref current);

			return canTraverse;
		}
        internal override bool IsValidNode(HtmlNode node)
        {
            if (node == null)
            {
                return false;
            }

            if (node.Tag == HtmlTag.TEXT)
            {
                return false;
            }

            if (node.Parent == null)
            {
                return false;
            }

            bool isValid = true;

            foreach (HtmlNode child in node.GetParent().GetChildren())
            {
                //There is a non text node other than current node. So the selector is not valid
                if (child != node && child.Tag != HtmlTag.TEXT)
                {
                    isValid = false;
                    break;
                }
            }

            return isValid;
        }
 internal override void Parse(HtmlNode node, List<HtmlStyle> htmlStyles)
 {
     if (string.IsNullOrEmpty(selectorText))
     {
         ApplyStyle(node, htmlStyles);
     }
     else
     {
         context.ParseSelectorOrBehavior(this.selectorText, CalculateSpecificity(SelectorType.Identity), node, htmlStyles);
     }
 }
        internal bool InheritStyle(HtmlStyle parentStyle, HtmlNode child)
        {
            foreach (CSSProperty property in properties)
            {
                if (property.AppendStyle(parentStyle, child))
                {
                    return true;
                }
            }

            return false;
        }
        private void ApplyToChildren(HtmlNode node, List<HtmlStyle> htmlStyles)
        {
            if (IsValidNode(node))
            {
                ApplyStyle(node, htmlStyles);

                foreach (HtmlNode child in node.GetChildren())
                {
                    ApplyToChildren(child, htmlStyles);
                }
            }
        }
        internal override void Parse(HtmlNode node, Specificity specificity, List<HtmlStyle> htmlStyles)
        {
            CSSelector nextSelector;
			
			if (context.ParseSelector(this.selectorText, out nextSelector))
			{
				if (nextSelector != null)
				{
                    ApplyStyle(nextSelector, specificity, node, htmlStyles);
				}
			}
        }
        private void ApplyStyle(CSSelector nextSelector, Specificity specificity, HtmlNode node, List<HtmlStyle> htmlStyles)
        {
            if (node.Next != null)
            {
            	if (nextSelector.IsValidNode(node.GetNext()))
                {
                    nextSelector.AddSpecificity(specificity);
            		nextSelector.Parse(node.GetNext(), htmlStyles);
                }

                ApplyStyle(nextSelector, specificity, node.GetNext(), htmlStyles);
            }
        }
        private void ApplyStyle(CSSelector nextSelector, Specificity specificity, HtmlNode node, List<HtmlStyle> htmlStyles)
		{
			if (nextSelector.IsValidNode(node))
			{
                nextSelector.AddSpecificity(specificity);
				nextSelector.Parse(node, htmlStyles);
			}

			foreach (HtmlNode child in node.GetChildren())
			{
                ApplyStyle(nextSelector.Clone(), specificity, child, htmlStyles);
			}
		}
 internal override void Parse(HtmlNode node, List<HtmlStyle> htmlStyles)
 {
     if (IsValidNode(node))
     {
         if (string.IsNullOrEmpty(this.selectorText))
         {
             ApplyStyle(node, htmlStyles);
         }
         else
         {
             context.ParseBehavior(this.selectorText, CalculateSpecificity(SelectorType.PseudoClass), node, htmlStyles);
         }
     }
 }
        public HtmlAnalyzer GetAnalyzer(int position, HtmlNode parent)
        {
            if (position < 0 || position > context.EOF)
            {
                throw new ArgumentOutOfRangeException("position");
            }

            CommentAnalyzer analyzer = new CommentAnalyzer(context);

            analyzer.startPosition = position;
            analyzer.parent = parent;

            return analyzer;
        }
        internal override bool IsValidNode(HtmlNode node)
        {
            if (node == null)
            {
                return false;
            }

            if (node.Tag == HtmlTag.TEXT)
            {
                return false;
            }

            return !HtmlStyle.IsNonStyleElement(node.Tag);
        }
        private void KeySeek(int position, HtmlNode node)
        {
            char letter = context.Html[position];
            mode = Mode.KeySeek;

            if (start == -1 && IsValidHtmlLetter(letter))
            {
                start = position;
            }
            else if (quote == char.MinValue && (letter == HtmlTag.singleQuote || letter == HtmlTag.doubleQuote))
            {
                start = position + 1;
                quote = letter;
            }
            else if (letter == HtmlTag.equalSign && start > -1 && position > start)
            {
                key = context.Html.Substring(start, position - start);
                start = -1;
                quote = char.MinValue;
                analyze = ValueSeek;
            }
            else if (start > -1 && quote != char.MinValue && start == position && letter == quote)//A quote is already opened and a close quote found with empty content inbetween. So resetting the indexes
            {
                start = -1;
                quote = char.MinValue;
            }
            else if (start > -1 && ((!IsValidHtmlLetter(letter) && quote == char.MinValue) ||
                letter == quote || (letter == HtmlTag.closeAngle && quote == char.MinValue)) && position > start)
            {
                key = context.Html.Substring(start, position - start);
                quote = char.MinValue;
                start = -1;

                if (letter != HtmlTag.closeAngle)
                {
                    analyze = AssignSeek;
                }
                else
                {
                    if (!string.IsNullOrEmpty(key) && !attributes.ContainsKey(key))
                    {
                        attributes.Add(key, string.Empty);
                        Clear();
                    }

                    analyze = null;
                }
            }
        }
        private void InheritFromParent(HtmlNode node, HtmlNode parent)
        {
            foreach (HtmlStyle style in node.HtmlStyles)
            {
                if (string.Compare(style.Value, "inherit", StringComparison.InvariantCultureIgnoreCase) == 0 && node.Parent != null)
                {
                    string value = FindParentStyle(parent, style.Name);

                    if (value != string.Empty)
                    {
                        style.ModifyStyle(value);
                    }
                }
            }
        }
		private bool FinilizeNodes(int position, ref HtmlNode current)
		{
			if (current != null)
			{
				current.Finilize(position);

				while (current.Parent != null)
				{
					current = current.GetParent();
					current.Finilize(position);
				}
			}

			return current != null;
		}
        private void AppendStyles(HtmlNode node, HtmlNode parent)
        {
            CSSPropertyParser propertyParser = new CSSPropertyParser();

            foreach (HtmlStyle parentStyle in parent.HtmlStyles)
            {
                if (!propertyParser.CanInherit(parentStyle.Name))
                {
                    continue;
                }

                bool found = false;

                if (propertyParser.InheritStyle(parentStyle, node))
                {
                    continue;
                }

                foreach (HtmlStyle childStyle in node.HtmlStyles)
                {
                    if (propertyParser.StyleContains(parentStyle, childStyle))
                    {
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    node.UpdateInheritedStyles(parentStyle);
                }
            }

            foreach (HtmlStyle parentStyle in parent.InheritedHtmlStyles)
            {
                if (!propertyParser.CanInherit(parentStyle.Name))
                {
                    continue;
                }

                if(parent.HasStyle(parentStyle.Name))
                {
                    continue;
                }

                propertyParser.InheritStyle(parentStyle, node);
            }
        }
        internal override void Parse(HtmlNode node, Specificity specificity, List<HtmlStyle> htmlStyles)
		{
			CSSelector nextSelector;
			
			if (context.ParseSelector(this.selectorText, out nextSelector))
			{
				if (nextSelector != null)
				{
					foreach (HtmlNode child in node.GetChildren())
					{
                        CSSelector clone = nextSelector.Clone();
                        ApplyStyle(clone, specificity, child, htmlStyles);
					}
				}
			}
		}
        public HtmlAnalyzer GetAnalyzer(int position, HtmlNode parent)
        {
            if (position < 0)
            {
                throw new ArgumentOutOfRangeException("position");
            }

            OpenTagAnalyzer analyzer = new OpenTagAnalyzer(context);

            analyzer.startPosition = position;
            analyzer.parent = parent;
            analyzer.tagStart = -1;
            analyzer.tag = string.Empty;

            return analyzer;
        }
        internal void ParseStyle(HtmlNode node)
        {
            foreach (CSSProperty property in properties)
            {
                property.ParseStyle(node);
            }

            foreach (HtmlNode child in node.GetChildren())
            {
                ParseStyle(child);
            }

            if (node.Parent == null && node.Next != null)
            {
                ParseStyle(node.GetNext());
            }
        }
        public void Init(int position, HtmlNode current)
        {
            if (startPosition < 0)
            {
                throw new ArgumentOutOfRangeException("position");
            }

            this.startPosition = position;
            this.current = current;
            this.tagStart = -1;
            this.tag = string.Empty;
            ignoreTag = current == null;

            if (current != null)
            {
                ignoreTag = string.IsNullOrEmpty(current.Tag);
            }
        }
示例#29
0
        internal void Parse(HtmlNode node)
        {
            foreach (var style in styles)
            {
                foreach (CSSelector selector in context.Selectors)
                {
                    if (selector.Prepare(style.Selector))
                    {
                        if (selector.IsValidNode(node))
                        {
                            selector.Parse(node, CloneStyles(style.HtmlStyles));
                        }

                        break;
                    }
                }
            }
        }
        private void ApplyToFirstChild(HtmlNode node, List<HtmlStyle> htmlStyles)
        {
            if (node.HasChildren)
            {
                HtmlNode child = node.GetChild(0);

                //Loop to skip empty text children
                while (child != null && child.Tag == HtmlTag.TEXT && child.Html.Trim() == string.Empty)
                {
                    child = child.GetNext();
                }

                if (child != null)
                {
                    ApplyStyle(child, htmlStyles);
                }
            }
        }