/// <summary> /// 创建选择器 /// </summary> /// <param name="expression">选择器表达式</param> /// <returns>选择器实例</returns> public static ICssSelector Create(string expression) { if (selectorCache.ContainsKey(expression)) { return(selectorCache[expression]); } var match = casecadingSelectorRegex.Match(expression); if (!match.Success) { throw new FormatException(); } ICssSelector selector = CssElementSelector.Create(match.Groups["leftSelector"].Value); foreach (var extraCapture in match.Groups["extra"].Captures.Cast <Capture>()) { var relative = extraCapture.FindCaptures(match.Groups["relative"]).Single().Value.Trim(); var rightSelector = extraCapture.FindCaptures(match.Groups["rightSelector"]).Single().Value.Trim(); selector = new CssCasecadingSelector(selector, relative, CssElementSelector.Create(rightSelector)); } lock ( _cacheSync ) { selectorCache[expression] = selector; } return(selector); }
/// <summary> /// 创建一个 CSS 选择器 /// </summary> /// <param name="expression">选择器表达式</param> /// <param name="scope">范畴限定</param> /// <returns>选择器</returns> public static ICssSelector Create(string expression, IHtmlContainer scope) { if (expression == null) { throw new ArgumentNullException("expression"); } ICssSelector[] selectors; if (_selectorCache.ContainsKey(expression)) { selectors = _selectorCache[expression]; } else { var match = cssSelectorRegex.Match(expression); if (!match.Success) { throw new FormatException("无法识别的CSS选择器"); } selectors = match.Groups["selector"].Captures.Cast <Capture>().Select(c => CssCasecadingSelector.Create(c.Value)).ToArray(); } lock ( _cacheSync ) { _selectorCache[expression] = selectors; } return(new CssMultipleSelector(selectors.Select(s => CssCasecadingSelector.Create(s, scope)).ToArray())); }
/// <summary> /// 创建带范畴限定的选择器 /// </summary> /// <param name="expression">选择器表达式</param> /// <param name="scope">范畴限定,上溯时不超出此范畴</param> /// <returns>带范畴限定的层叠选择器</returns> public static ISelector Create(IHtmlContainer scope, string expression) { if (scope == null) { throw new ArgumentNullException("scope"); } if (expression == null) { throw new ArgumentNullException("expression"); } return(CssCasecadingSelector.Create(new CssAncetorRelativeSelector(new ContainerRestrict(scope)), CssParser.ParseSelector(expression))); }
/// <summary> /// 合并两个关系选择器 /// </summary> /// <param name="left">左关系选择器</param> /// <param name="right">右关系选择器</param> /// <returns>合并后的关系选择器</returns> public static CssRelativeSelector Combine(CssRelativeSelector left, CssRelativeSelector right) { if (left == null) { throw new ArgumentNullException("left"); } if (right == null) { throw new ArgumentNullException("right"); } var selector = right.LeftSelector; var combinator = right.Combinator; var casecadingSelector = selector as CssCasecadingSelector; if (casecadingSelector != null) //如果右边关系选择器的左选择器是一个层叠选择器 { return(CreateRelativeSelector(CssCasecadingSelector.Combine(left, casecadingSelector), combinator)); //将层叠选择器与左边的关系选择器合并,得到一个新的层叠选择器,再根据结合符创建新的关系选择器。 } /* * 举例说明如下: * 假设左关系选择器是 p>,右关系选择器是 div>ul>li+ * 则右关系选择器的左选择器(selector)是div>ul>li,结合符(combinator)是+。 * 将selector与左边的关系选择器合并,得到:p>div>ul>li,再与结合符结合得到新的关系选择器:p>div>ul>li+ */ var elementSelector = selector as CssElementSelector; if (elementSelector != null) { return(CreateRelativeSelector(new CssCasecadingSelector(left, elementSelector), combinator)); } throw new NotSupportedException(); }
/// <summary> /// 在元素集所有子代元素中使用 CSS 选择器选出符合要求的元素 /// </summary> /// <param name="elements">作为选择范围的元素集</param> /// <param name="expression">CSS 选择器表达式</param> /// <returns>符合选择器的所有子代</returns> public static IEnumerable <IHtmlElement> Find(this IEnumerable <IHtmlElement> elements, string expression) { if (!elements.Any()) { return(Enumerable.Empty <IHtmlElement>()); } if (elements.IsSingle()) { return(elements.Single().Find(expression)); } var document = elements.First().Document; if (elements.Any(e => !e.Document.Equals(document))) { throw new InvalidOperationException("不支持在不同的文档中搜索"); } var selector = CssCasecadingSelector.Create(expression, elements); return(selector.Filter(document.Descendants())); }
/// <summary> /// 创建层叠选择器 /// </summary> /// <param name="leftSelector">左选择器</param> /// <param name="combanitor">结合符</param> /// <param name="rightSelector">右选择器</param> /// <returns>层叠选择器</returns> private static ISelector CreateCasecadingSelector(ISelector leftSelector, char combanitor, CssElementSelector rightSelector) { return(CssCasecadingSelector.Create(leftSelector, combanitor, rightSelector)); }
/// <summary> /// 合并关系选择器和层叠选择器 /// </summary> /// <param name="relativeSelector">关系选择器</param> /// <param name="selector">层叠选择器</param> /// <returns></returns> internal static CssCasecadingSelector Combine(CssRelativeSelector relativeSelector, CssCasecadingSelector selector) { relativeSelector = Combine(relativeSelector, selector.RelativeSelector); return(new CssCasecadingSelector(relativeSelector, selector.LastSelector)); }
/// <summary> /// 调用此方法预热选择器 /// </summary> public static void WarmUp() { cssSelectorRegex.IsMatch(""); CssCasecadingSelector.WarmUp(); }
/// <summary> /// 合并关系选择器和层叠选择器 /// </summary> /// <param name="relativeSelector">关系选择器</param> /// <param name="selector">层叠选择器</param> /// <returns></returns> internal static CssCasecadingSelector Combine( CssRelativeSelector relativeSelector, CssCasecadingSelector selector ) { relativeSelector = Combine( relativeSelector, selector.RelativeSelector ); return new CssCasecadingSelector( relativeSelector, selector.LastSelector ); }
public static ICssSelector Combine(CssRelativeSelector relativeSelector, CssMultipleSelector multipleSelector) { return(new CssMultipleSelector(multipleSelector._selectors.Select(selector => CssCasecadingSelector.Create(relativeSelector, selector)).ToArray())); }