internal static bool IsMatch(this HtmlAgilityPack.HtmlNode node, IEnumerable <SimpleSelector> selectors) { var stack = new Stack <SimpleSelector>(selectors); var currentRule = stack.Pop(); if (!node.IsMatch(currentRule, stack)) { return(false); } //no more selectors, its a match if (!stack.Any()) { return(true); } var currentNode = node.ParentNode; currentRule = stack.Pop(); while (currentNode != null) { if (currentNode.IsMatch(currentRule, stack)) { if (stack.Any()) { currentRule = stack.Pop(); } else { //no more rules left to match ad we still have ode context then return true return(true); } } //keep moving up the dom currentNode = currentNode.ParentNode; } //We must still have unmatched css selectors return(false); }
internal static bool IsMatch(this HtmlAgilityPack.HtmlNode node, SimpleSelector selector, Stack <SimpleSelector> remainingStack) { if (!string.IsNullOrEmpty(selector.ElementName) && node.Name != selector.ElementName) { return(false); } if (!string.IsNullOrEmpty(selector.ID) && node.Id != selector.ID) { return(false); } if (!string.IsNullOrEmpty(selector.Class)) { var classString = node.Attributes.Contains("class") ? node.Attributes["class"].Value : ""; if (!classString.Split(' ').Contains(selector.Class)) { return(false); } } if (!string.IsNullOrEmpty(selector.Pseudo)) { if (!node.IsPseudoMatch(selector, remainingStack)) { return(false); } } if (selector.Combinator != null && remainingStack.Any()) { var nextSel = remainingStack.Pop(); switch (selector.Combinator.Value) { case Combinator.ChildOf: if (node.ParentNode == null) //has to be a child of something { return(false); } if (!node.ParentNode.IsMatch(nextSel, remainingStack)) { return(false); } break; case Combinator.Namespace: //we are not going to support this until I see a valid use case return(false); case Combinator.PrecededBy: if (!node.PreviousSiblingsNotText().Any(x => x.IsMatch(nextSel, remainingStack))) { return(false); } break; case Combinator.PrecededImmediatelyBy: var sib = node.PreviousSiblingNotText(); if (sib == null) //has to be a child of something { return(false); } if (!sib.IsMatch(nextSel, remainingStack)) { return(false); } break; default: break; } } if (selector.Attribute != null) { if (!node.IsMatch(selector.Attribute)) { return(false); } } if (selector.Child != null) { return(node.IsMatch(selector.Child, remainingStack)); } return(true); }
internal static IEnumerable <Selector> Matches(this HtmlAgilityPack.HtmlNode node, IEnumerable <Selector> selectors) { return(selectors.Where(x => node.IsMatch(x.SimpleSelectors))); }