#region Copyright and License // // Fizzler - CSS Selector Engine for Microsoft .NET Framework // Copyright (c) 2009 Atif Aziz, Colin Ramsay. All rights reserved. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General Public License // along with this library; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // #endregion namespace Fizzler { #region Imports using System; using System.Collections.Generic; using System.Linq; #endregion /// /// A selector generator implementation for an arbitrary document/element system. /// public class SelectorGenerator : ISelectorGenerator { private readonly IEqualityComparer _equalityComparer; private readonly Stack> _selectors; /// /// Initializes a new instance of this object with an instance /// of and the default equality /// comparer that is used for determining if two elements are equal. /// public SelectorGenerator(IElementOps ops) : this(ops, null) {} /// /// Initializes a new instance of this object with an instance /// of and an equality comparer /// used for determining if two elements are equal. /// public SelectorGenerator(IElementOps ops, IEqualityComparer equalityComparer) { if(ops == null) throw new ArgumentNullException("ops"); Ops = ops; _equalityComparer = equalityComparer ?? EqualityComparer.Default; _selectors = new Stack>(); } /// /// Gets the selector implementation. /// /// /// If the generation is not complete, this property returns the /// last generated selector. /// public Selector Selector { get; private set; } /// /// Gets the instance that this object /// was initialized with. /// public IElementOps Ops { get; private set; } /// /// Returns the collection of selector implementations representing /// a group. /// /// /// If the generation is not complete, this method return the /// selectors generated so far in a group. /// public IEnumerable> GetSelectors() { var selectors = _selectors; var top = Selector; return top == null ? selectors.Select(s => s) : selectors.Concat(Enumerable.Repeat(top, 1)); } /// /// Adds a generated selector. /// protected void Add(Selector selector) { if(selector == null) throw new ArgumentNullException("selector"); var top = Selector; Selector = top == null ? selector : (elements => selector(top(elements))); } /// /// Delimits the initialization of a generation. /// public virtual void OnInit() { _selectors.Clear(); Selector = null; } /// /// Delimits a selector generation in a group of selectors. /// public virtual void OnSelector() { if (Selector != null) _selectors.Push(Selector); Selector = null; } /// /// Delimits the closing/conclusion of a generation. /// public virtual void OnClose() { var sum = GetSelectors().Aggregate((a, b) => (elements => a(elements).Concat(b(elements)))); var normalize = Ops.Descendant(); Selector = elements => sum(normalize(elements)).Distinct(_equalityComparer); _selectors.Clear(); } /// /// Generates a ID selector, /// which represents an element instance that has an identifier that /// matches the identifier in the ID selector. /// public virtual void Id(string id) { Add(Ops.Id(id)); } /// /// Generates a class selector, /// which is an alternative when /// representing the class attribute. /// public virtual void Class(string clazz) { Add(Ops.Class(clazz)); } /// /// Generates a type selector, /// which represents an instance of the element type in the document tree. /// public virtual void Type(NamespacePrefix prefix, string type) { Add(Ops.Type(prefix, type)); } /// /// Generates a universal selector, /// any single element in the document tree in any namespace /// (including those without a namespace) if no default namespace /// has been specified for selectors. /// public virtual void Universal(NamespacePrefix prefix) { Add(Ops.Universal(prefix)); } /// /// Generates an attribute selector /// that represents an element with the given attribute /// whatever the values of the attribute. /// public virtual void AttributeExists(NamespacePrefix prefix, string name) { Add(Ops.AttributeExists(prefix, name)); } /// /// Generates an attribute selector /// that represents an element with the given attribute /// and whose value is exactly . /// public virtual void AttributeExact(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributeExact(prefix, name, value)); } /// /// Generates an attribute selector /// that represents an element with the given attribute /// and whose value is a whitespace-separated list of words, one of /// which is exactly . /// public virtual void AttributeIncludes(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributeIncludes(prefix, name, value)); } /// /// Generates an attribute selector /// that represents an element with the given attribute , /// its value either being exactly or beginning /// with immediately followed by "-" (U+002D). /// public virtual void AttributeDashMatch(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributeDashMatch(prefix, name, value)); } /// /// Generates an attribute selector /// that represents an element with the attribute /// whose value begins with the prefix . /// public void AttributePrefixMatch(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributePrefixMatch(prefix, name, value)); } /// /// Generates an attribute selector /// that represents an element with the attribute /// whose value ends with the suffix . /// public void AttributeSuffixMatch(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributeSuffixMatch(prefix, name, value)); } /// /// Generates an attribute selector /// that represents an element with the attribute /// whose value contains at least one instance of the substring . /// public void AttributeSubstring(NamespacePrefix prefix, string name, string value) { Add(Ops.AttributeSubstring(prefix, name, value)); } /// /// Generates a pseudo-class selector, /// which represents an element that is the first child of some other element. /// public virtual void FirstChild() { Add(Ops.FirstChild()); } /// /// Generates a pseudo-class selector, /// which represents an element that is the last child of some other element. /// public virtual void LastChild() { Add(Ops.LastChild()); } /// /// Generates a pseudo-class selector, /// which represents an element that is the N-th child of some other element. /// public virtual void NthChild(int a, int b) { Add(Ops.NthChild(a, b)); } /// /// Generates a pseudo-class selector, /// which represents an element that has a parent element and whose parent /// element has no other element children. /// public virtual void OnlyChild() { Add(Ops.OnlyChild()); } /// /// Generates a pseudo-class selector, /// which represents an element that has no children at all. /// public virtual void Empty() { Add(Ops.Empty()); } /// /// Generates a combinator, /// which represents a childhood relationship between two elements. /// public virtual void Child() { Add(Ops.Child()); } /// /// Generates a combinator, /// which represents a relationship between two elements where one element is an /// arbitrary descendant of some ancestor element. /// public virtual void Descendant() { Add(Ops.Descendant()); } /// /// Generates a combinator, /// which represents elements that share the same parent in the document tree and /// where the first element immediately precedes the second element. /// public virtual void Adjacent() { Add(Ops.Adjacent()); } /// /// Generates a combinator, /// which separates two sequences of simple selectors. The elements represented /// by the two sequences share the same parent in the document tree and the /// element represented by the first sequence precedes (not necessarily /// immediately) the element represented by the second one. /// public virtual void GeneralSibling() { Add(Ops.GeneralSibling()); } /// /// Generates a pseudo-class selector, /// which represents an element that is the N-th child from bottom up of some other element. /// public void NthLastChild(int a, int b) { Add(Ops.NthLastChild(a, b)); } } }