AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.2.4" />

 ComplexSelector

Represents a complex selector. One or more compound selectors separated by combinators.
using AngleSharp.DOM.Collections; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace AngleSharp.DOM.Css { internal class ComplexSelector : Selector { private struct CombinatorSelector { public char delimiter; public Func<Element, IEnumerable<Element>> transform; public Selector selector; } private List<CombinatorSelector> selectors; public override int Specifity { get { int num = 0; for (int i = 0; i < selectors.Count; i++) { num += selectors[i].selector.Specifity; } return num; } } public int Length => selectors.Count; public bool IsReady { get; set; } public ComplexSelector() { selectors = new List<CombinatorSelector>(); } public override bool Match(Element element) { int num = selectors.Count - 1; if (selectors[num].selector.Match(element)) { if (num > 0) return MatchCascade(num - 1, element); return true; } return false; } public ComplexSelector ConcludeSelector(Selector selector) { if (!IsReady) { selectors.Add(new CombinatorSelector { selector = selector, transform = null }); IsReady = true; } return this; } public ComplexSelector AppendSelector(Selector selector, CssCombinator combinator) { if (IsReady) return this; Func<Element, IEnumerable<Element>> func = null; char delimiter; switch (combinator) { case CssCombinator.Child: delimiter = '>'; func = ((Element el) => Single(el.ParentElement)); break; case CssCombinator.AdjacentSibling: delimiter = '+'; func = ((Element el) => Single(el.PreviousElementSibling)); break; case CssCombinator.Descendent: delimiter = ' '; func = delegate(Element el) { List<Element> list = new List<Element>(); for (Element parentElement = el.ParentElement; parentElement != null; parentElement = parentElement.ParentElement) { list.Add(parentElement); } return list; }; break; case CssCombinator.Sibling: delimiter = '~'; func = delegate(Element el) { Element parentElement2 = el.ParentElement; if (parentElement2 == null) return new Element[0]; HTMLCollection children = parentElement2.Children; bool flag = false; List<Element> list2 = new List<Element>(); for (int num = children.Length - 1; num >= 0; num--) { if (children[num] == el) flag = true; else if (flag) { list2.Add(children[num]); } } return list2; }; break; default: return this; } selectors.Add(new CombinatorSelector { selector = selector, transform = func, delimiter = delimiter }); return this; } public ComplexSelector ClearSelectors() { IsReady = false; selectors.Clear(); return this; } private bool MatchCascade(int pos, Element element) { IEnumerable<Element> enumerable = selectors[pos].transform(element); foreach (Element item in enumerable) { if (selectors[pos].selector.Match(item) && (pos == 0 || MatchCascade(pos - 1, item))) return true; } return false; } private static IEnumerable<Element> Single(Element element) { if (element == null) return Enumerable.Empty<Element>(); return new Element[1] { element }; } public override string ToCss() { StringBuilder stringBuilder = new StringBuilder(); if (selectors.Count > 0) { int num = selectors.Count - 1; for (int i = 0; i < num; i++) { stringBuilder.Append(selectors[i].selector.ToCss()).Append(selectors[i].delimiter); } stringBuilder.Append(selectors[num].selector.ToCss()); } return stringBuilder.ToString(); } } }