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); } }
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); } } }