Ejemplo n.º 1
0
        /// <summary>
        /// Parse single argument passed to a pseudoselector
        /// </summary>
        ///
        /// <exception cref="ArgumentException">
        /// Thrown when one or more arguments have unsupported or illegal values.
        /// </exception>
        /// <exception cref="NotImplementedException">
        /// Thrown when the requested operation is unimplemented.
        /// </exception>
        ///
        /// <param name="value">
        /// The arguments.
        /// </param>
        ///
        /// <returns>
        /// The parsed string
        /// </returns>

        protected string ParseSingleArg(string value)
        {
            IStringScanner scanner = Scanner.Create(value);

            var quoting = ParameterQuoted(0);

            switch (quoting)
            {
            case QuotingRule.OptionallyQuoted:
                scanner.Expect(MatchFunctions.OptionallyQuoted());
                if (!scanner.Finished)
                {
                    throw new ArgumentException(InvalidArgumentsError());
                }
                return(scanner.Match);

            case QuotingRule.AlwaysQuoted:

                scanner.Expect(MatchFunctions.Quoted());
                if (!scanner.Finished)
                {
                    throw new ArgumentException(InvalidArgumentsError());
                }
                return(scanner.Match);

            case QuotingRule.NeverQuoted:
                return(value);

            default:
                throw new NotImplementedException("Unimplemented quoting rule");
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Get the value of a style property for the first element in the set of matched elements, and
        /// converts to a numeric type T. Any numeric type strings are ignored when converting to numeric
        /// values.
        /// </summary>
        ///
        /// <typeparam name="T">
        /// The type. This should probably be a numeric type, but the method will attempt to convert to
        /// any IConvertible type passed.
        /// </typeparam>
        /// <param name="style">
        /// The name of the CSS style to retrieve.
        /// </param>
        ///
        /// <returns>
        /// A value of type T.
        /// </returns>
        ///
        /// <url>
        /// http://api.jquery.com/css/#css1
        /// </url>

        public T Css <T>(String style) where T : IConvertible
        {
            IDomElement el = FirstElement();

            if (el == null)
            {
                return(default(T));
            }


            if (Objects.IsNumericType(typeof(T)))
            {
                IStringScanner scanner = Scanner.Create(el.Style[style] ?? "");
                T num;
                if (scanner.TryGetNumber <T>(out num))
                {
                    return(num);
                }
                else
                {
                    return(default(T));
                }
            }
            else
            {
                return((T)Objects.ChangeType(el.Style[style] ?? "", typeof(T)));
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Parse the arguments using the rules returned by the ParameterQuoted method.
        /// </summary>
        ///
        /// <param name="value">
        /// The arguments
        /// </param>
        ///
        /// <returns>
        /// An array of strings
        /// </returns>

        protected string[] ParseArgs(string value)
        {
            List <string> parms = new List <string>();
            int           index = 0;


            IStringScanner scanner = Scanner.Create(value);

            while (!scanner.Finished)
            {
                var quoting = ParameterQuoted(index);
                switch (quoting)
                {
                case QuotingRule.OptionallyQuoted:
                    scanner.Expect(MatchFunctions.OptionallyQuoted(","));
                    break;

                case QuotingRule.AlwaysQuoted:
                    scanner.Expect(MatchFunctions.Quoted());
                    break;

                case QuotingRule.NeverQuoted:
                    scanner.Seek(',', true);
                    break;

                default:
                    throw new NotImplementedException("Unimplemented quoting rule");
                }

                parms.Add(scanner.Match);
                if (!scanner.Finished)
                {
                    scanner.Next();
                    index++;
                }
            }
            return(parms.ToArray());
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns the numeric value only of a style, ignoring units
        /// </summary>
        ///
        /// <param name="style">
        /// The style.
        /// </param>
        ///
        /// <returns>
        /// A double, or null if the style did not exist or did not contain a numeric value.
        /// </returns>

        public double?NumberPart(string style)
        {
            string st = GetStyle(style);

            if (st == null)
            {
                return(null);
            }
            else
            {
                IStringScanner scanner = Scanner.Create(st);
                string         numString;
                if (scanner.TryGet(MatchFunctions.Number(), out numString))
                {
                    double num;
                    if (double.TryParse(numString, out num))
                    {
                        return(num);
                    }
                }
                return(null);
            }
        }
Ejemplo n.º 5
0
        public IEnumerable <Selector> Parse(string selector)
        {
            Selectors = new List <Selector>();

            string sel = (selector ?? String.Empty).Trim();

            if (IsHtml(selector))
            {
                Current.Html         = sel;
                Current.SelectorType = SelectorType.HTML;
                Selectors.Add(Current);
                return(Selectors);
            }
            scanner = Scanner.Create(sel);

            while (!scanner.Finished)
            {
                switch (scanner.NextChar)
                {
                case '*':
                    Current.SelectorType = SelectorType.All;
                    scanner.Next();
                    break;

                case '<':
                    // not selecting - creating html
                    Current.Html = sel;
                    scanner.End();
                    break;

                case ':':
                    scanner.Next();
                    string key = scanner.Get(MatchFunctions.PseudoSelector);
                    switch (key)
                    {
                    case "checkbox":
                    case "radio":
                    case "button":
                    case "file":
                    case "text":
                    case "password":
                        StartNewSelector(SelectorType.Attribute);

                        //Current.SelectorType |= SelectorType.Attribute;
                        Current.AttributeSelectorType = AttributeSelectorType.Equals;
                        Current.AttributeName         = "type";
                        Current.AttributeValue        = key;

                        if (key == "button" && !Current.SelectorType.HasFlag(SelectorType.Tag))
                        {
                            //StartNewSelector(CombinatorType.Cumulative);
                            StartNewSelector(SelectorType.Tag, CombinatorType.Cumulative, Current.TraversalType);
                            //Current.SelectorType = SelectorType.Tag;
                            Current.Tag = "button";
                        }
                        break;

                    case "checked":
                    case "selected":
                    case "disabled":
                        StartNewSelector(SelectorType.Attribute);
                        Current.AttributeSelectorType = AttributeSelectorType.Exists;
                        Current.AttributeName         = key;
                        break;

                    case "enabled":
                        StartNewSelector(SelectorType.Attribute);
                        Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                        Current.AttributeName         = "disabled";
                        break;

                    case "contains":

                        StartNewSelector(SelectorType.Contains);
                        IStringScanner inner = scanner.ExpectBoundedBy('(', true).ToNewScanner();
                        Current.Criteria = inner.Get(MatchFunctions.OptionallyQuoted);
                        break;

                    case "eq":
                    case "gt":
                    case "lt":
                        StartNewSelector(SelectorType.Position);
                        switch (key)
                        {
                        case "eq": Current.PositionType = PositionType.IndexEquals; break;

                        case "lt": Current.PositionType = PositionType.IndexLessThan; break;

                        case "gt": Current.PositionType = PositionType.IndexGreaterThan; break;
                        }

                        scanner.ExpectChar('(');
                        Current.PositionIndex = Convert.ToInt32(scanner.GetNumber());
                        scanner.ExpectChar(')');

                        break;

                    case "even":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.Even;
                        break;

                    case "odd":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.Odd;
                        break;

                    case "first":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.First;
                        break;

                    case "last":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.Last;
                        break;

                    case "last-child":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.LastChild;
                        break;

                    case "first-child":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.FirstChild;
                        break;

                    case "nth-child":
                        StartNewSelector(SelectorType.Position);
                        Current.PositionType = PositionType.NthChild;
                        Current.Criteria     = scanner.GetBoundedBy('(');
                        break;

                    case "has":
                    case "not":
                        StartNewSelector(key == "has" ? SelectorType.SubSelectorHas : SelectorType.SubSelectorNot);
                        Current.TraversalType = TraversalType.Descendent;

                        string        criteria     = Current.Criteria = scanner.GetBoundedBy('(', true);
                        SelectorChain subSelectors = new SelectorChain(criteria);
                        Current.SubSelectors.Add(subSelectors);
                        break;

                    case "visible":
                        StartNewSelector(SelectorType.Other);
                        Current.OtherType = OtherType.Visible;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException("Unknown pseudoselector :\"" + key + "\"");
                    }
                    break;

                case '.':
                    StartNewSelector(SelectorType.Class);
                    scanner.Next();
                    Current.Class = scanner.Get(MatchFunctions.CssClass);
                    break;

                case '#':

                    scanner.Next();
                    if (!scanner.Finished)
                    {
                        StartNewSelector(SelectorType.ID);
                        Current.ID = scanner.Get(MatchFunctions.HtmlIDValue);
                    }

                    break;

                case '[':
                    StartNewSelector(SelectorType.Attribute);

                    IStringScanner innerScanner = scanner.ExpectBoundedBy('[', true).ToNewScanner();
                    Current.AttributeName = innerScanner.Get(MatchFunctions.HTMLAttribute);
                    innerScanner.SkipWhitespace();

                    if (innerScanner.Finished)
                    {
                        Current.AttributeSelectorType = AttributeSelectorType.Exists;
                    }
                    else
                    {
                        string matchType = innerScanner.Get("=", "^=", "*=", "~=", "$=", "!=");
                        Current.AttributeValue = innerScanner.Get(expectsOptionallyQuotedValue());
                        switch (matchType)
                        {
                        case "=":
                            Current.AttributeSelectorType = AttributeSelectorType.Equals;
                            break;

                        case "^=":
                            Current.AttributeSelectorType = AttributeSelectorType.StartsWith;
                            break;

                        case "*=":
                            Current.AttributeSelectorType = AttributeSelectorType.Contains;
                            break;

                        case "~=":
                            Current.AttributeSelectorType = AttributeSelectorType.ContainsWord;
                            break;

                        case "$=":
                            Current.AttributeSelectorType = AttributeSelectorType.EndsWith;
                            break;

                        case "!=":
                            Current.AttributeSelectorType = AttributeSelectorType.NotEquals;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException("Unknown attibute matching operator '" + matchType + "'");
                        }
                    }

                    break;

                case ',':
                    FinishSelector();
                    scanner.NextNonWhitespace();
                    break;

                case '>':
                    if (Current.IsComplete)
                    {
                        StartNewSelector(TraversalType.Child);
                    }
                    else
                    {
                        Current.TraversalType = TraversalType.Child;
                    }

                    // This is a wierd thing because if you use the > selector against a set directly, the meaning is "filter"
                    // whereas if it is used in a combination selector the meaning is "filter for 1st child"
                    Current.ChildDepth = (Current.CombinatorType == CombinatorType.Root ? 0 : 1);
                    scanner.NextNonWhitespace();
                    break;

                case ' ':
                    // if a ">" or "," is later found, it will be overridden.
                    scanner.NextNonWhitespace();
                    StartNewSelector(TraversalType.Descendent);
                    break;

                default:

                    string tag = "";
                    if (scanner.TryGet(MatchFunctions.HTMLTagName, out tag))
                    {
                        StartNewSelector(SelectorType.Tag);
                        Current.Tag = tag;
                    }
                    else
                    {
                        if (scanner.Pos == 0)
                        {
                            Current.Html         = sel;
                            Current.SelectorType = SelectorType.HTML;
                            scanner.End();
                        }
                        else
                        {
                            throw new InvalidOperationException(scanner.LastError);
                        }
                    }

                    break;
                }
            }
            // Close any open selectors
            FinishSelector();
            return(Selectors);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Parse the string, and return a sequence of Selector objects
        /// </summary>
        /// <param name="selector"></param>
        /// <returns></returns>
        public Selector Parse(string selector)
        {
            Selectors = new Selector();

            string sel = (selector ?? String.Empty).Trim();

            if (IsHtml(selector))
            {
                Current.Html = sel;
                Current.SelectorType = SelectorType.HTML;
                Selectors.Add(Current);
                return Selectors;
            }
            
            scanner = Scanner.Create(sel);

            while (!scanner.Finished)
            {
                switch (scanner.Current)
                {
                    case '*':
                        StartNewSelector(SelectorType.All);
                        scanner.Next();
                        break;
                    case '<':
                        // not selecting - creating html
                        Current.Html = sel;
                        scanner.End();
                        break;
                    case ':':
                        scanner.Next();
                        string key = scanner.Get(MatchFunctions.PseudoSelector).ToLower();
                        switch (key)
                        {
                            case "input":
                                AddTagSelector("input");
                                AddTagSelector("textarea",true);
                                AddTagSelector("select",true);
                                AddTagSelector("button",true);
                                break;
                            case "text":
                                StartNewSelector(SelectorType.AttributeValue | SelectorType.Tag);
                                Current.Tag = "input";
                                Current.AttributeSelectorType = AttributeSelectorType.Equals;
                                Current.AttributeName = "type";
                                Current.AttributeValue = "text";
                                
                                StartNewSelector(SelectorType.AttributeValue | SelectorType.Tag, CombinatorType.Grouped, Current.TraversalType);
                                Current.Tag = "input";
                                Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                                Current.AttributeName = "type";

                                Current.SelectorType |= SelectorType.Tag;
                            Current.Tag = "input";
                                break;

                            case "checkbox":
                            case "radio":
                            case "button":
                            case "file":
                            case "image":
                            case "password":
                                AddInputSelector(key,"input");
                                break;
                            case "reset":
                            case "submit":
                                AddInputSelector(key);
                                break;
                            case "checked":
                            case "selected":
                            case "disabled":
                                StartNewSelector(SelectorType.AttributeValue);
                                Current.AttributeSelectorType = AttributeSelectorType.Exists;
                                Current.AttributeName = key;
                                break;
                            case "enabled":
                                StartNewSelector(SelectorType.AttributeValue);
                                Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                                Current.AttributeName = "disabled";
                                break;
                        
                            case "first-letter":
                            case "first-line":
                            case "before":
                            case "after":
                                throw new NotImplementedException("The CSS pseudoelement selectors are not implemented in CsQuery.");
                            case "target":
                            case "link":
                            case "hover":
                            case "active":
                            case "focus":
                            case "visited":
                                throw new NotImplementedException("Pseudoclasses that require a browser aren't implemented.");

                            default:
                                if (!AddPseudoSelector(key)) {
                                
                                    throw new ArgumentException("Unknown pseudo-class :\"" + key + "\". If this is a valid CSS or jQuery selector, please let us know.");
                                }
                                break;
                        }
                        break;
                    case '.':
                        StartNewSelector(SelectorType.Class);
                        scanner.Next();
                        Current.Class = scanner.Get(MatchFunctions.CssClassName);
                        break;
                    case '#':

                        scanner.Next();
                        if (!scanner.Finished)
                        {
                            StartNewSelector(SelectorType.ID);
                            Current.ID = scanner.Get(MatchFunctions.HtmlIDValue());
                        }

                        break;
                    case '[':
                        StartNewSelector(SelectorType.AttributeValue);

                        IStringScanner innerScanner = scanner.ExpectBoundedBy('[', true).ToNewScanner();
                        
                        Current.AttributeName = innerScanner.Get(MatchFunctions.HTMLAttribute());
                        innerScanner.SkipWhitespace();

                        if (innerScanner.Finished)
                        {
                            Current.AttributeSelectorType = AttributeSelectorType.Exists;
                        }
                        else
                        {
                            string matchType = innerScanner.Get("=", "^=", "*=", "~=", "$=", "!=","|=");

                            // CSS allows [attr=] as a synonym for [attr]
                            if (innerScanner.Finished)
                            {
                                Current.AttributeSelectorType = AttributeSelectorType.Exists;
                            } 
                            else 
                            {
                                var rawValue = innerScanner.Expect(expectsOptionallyQuotedValue()).ToNewScanner();

                                Current.AttributeValue = rawValue.Finished ? 
                                    "" : 
                                    rawValue.Get(new EscapedString());

                                switch (matchType)
                                {

                                    case "=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.Equals;
                                        break;
                                    case "^=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.StartsWith;
                                        // attributevalue starts with "" matches nothing
                                        if (Current.AttributeValue == "")
                                        {
                                            Current.AttributeValue = "" + (char)0;
                                        }
                                        break;
                                    case "*=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.Contains;
                                        break;
                                    case "~=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.ContainsWord;
                                        break;
                                    case "$=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.EndsWith;
                                        break;
                                    case "!=":
                                        Current.AttributeSelectorType = AttributeSelectorType.NotEquals;
                                        // must matched manually - missing also validates as notEquals
                                        break;
                                    case "|=":
                                        Current.SelectorType |= SelectorType.AttributeValue;
                                        Current.AttributeSelectorType = AttributeSelectorType.StartsWithOrHyphen;

                                        break;
                                    default:
                                        throw new ArgumentException("Unknown attibute matching operator '" + matchType + "'");
                                }
                            }
                        }

                        break;
                    case ',':
                        FinishSelector();
                        NextCombinatorType = CombinatorType.Root;
                        NextTraversalType = TraversalType.All;
                        scanner.NextNonWhitespace();
                        break;
                    case '+':
                        StartNewSelector(TraversalType.Adjacent);
                        scanner.NextNonWhitespace();
                        break;
                    case '~':
                        StartNewSelector(TraversalType.Sibling);
                        scanner.NextNonWhitespace();
                        break;
                    case '>':
                        StartNewSelector(TraversalType.Child);
                        // This is a wierd thing because if you use the > selector against a set directly, the meaning is "filter" 
                        // whereas if it is used in a combination selector the meaning is "filter for 1st child"
                        //Current.ChildDepth = (Current.CombinatorType == CombinatorType.Root ? 0 : 1);
                        Current.ChildDepth = 1;
                        scanner.NextNonWhitespace();
                        break;
                    case ' ':
                        // if a ">" or "," is later found, it will be overridden.
                        scanner.NextNonWhitespace();
                        NextTraversalType = TraversalType.Descendent;
                        break;
                    default:

                        string tag = "";
                        if (scanner.TryGet(MatchFunctions.HTMLTagSelectorName(), out tag))
                        {
                            AddTagSelector(tag);
                        }
                        else
                        {
                            if (scanner.Index == 0)
                            {
                                Current.Html = sel;
                                Current.SelectorType = SelectorType.HTML;
                                scanner.End();
                            }
                            else
                            {
                                throw new ArgumentException(scanner.LastError);
                            }

                        }

                        break;
                }
            }
            // Close any open selectors
            FinishSelector();
            if (Selectors.Count == 0)
            {
                var empty = new SelectorClause
                {
                    SelectorType = SelectorType.None,
                    TraversalType = TraversalType.Filter
                };
                Selectors.Add(empty);
                
            }
            return Selectors;
        }
Ejemplo n.º 7
0
        public IOperand Parse <T>(string text) where T : IConvertible
        {
            IsTyped = typeof(T) != typeof(IConvertible);
            scanner = Scanner.Create(text);

            Clause = IsTyped ?
                     new Sum <T>() :
                     new Sum();

            // it could have just one operand
            IOperand lastOperand = GetOperand <T>();

            Clause.AddOperand(lastOperand);
            IOperation working     = Clause;
            IOperand   nextOperand = null;

            while (!ParseEnd)
            {
                IOperator op = GetOperation();

                nextOperand = GetOperand <T>();
                IOperation newOp;

                if (op.AssociationType == working.AssociationType)
                {
                    // working can only be sum/product
                    working.AddOperand(nextOperand, op.IsInverted);
                }
                else
                {
                    switch (op.AssociationType)
                    {
                    case AssociationType.Addition:
                        // always return to the root when adding
                        if (!ReferenceEquals(working, Clause))
                        {
                            working = Clause;
                        }
                        working.AddOperand(nextOperand, op.IsInverted);
                        break;

                    case AssociationType.Multiplicaton:
                        //"steal" last operand from Clause, and change working to the new op
                        newOp = op.GetFunction();

                        newOp.AddOperand(lastOperand);
                        newOp.AddOperand(nextOperand, op.IsInverted);
                        Clause.ReplaceLastOperand(newOp);
                        working = newOp;
                        break;

                    case AssociationType.Power:
                        // Similar to Multiplication, but does not change the active chain to the new operation. It can never be added to.
                        newOp = op.GetFunction();

                        newOp.AddOperand(lastOperand);
                        newOp.AddOperand(nextOperand, op.IsInverted);
                        Clause.ReplaceLastOperand(newOp);
                        break;

                    case AssociationType.Function:
                        // Similar to Multiplication, but does not change the active chain to the new operation. It can never be added to.
                        newOp = op.GetFunction();
                        newOp.AddOperand(nextOperand, op.IsInverted);
                        Clause.ReplaceLastOperand(newOp);
                        break;

                    default:
                        throw new NotImplementedException("Unknown association type.");
                    }
                }
                lastOperand = nextOperand;
            }
            Error = "";

            return((IOperand)Clause);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Parse the string, and return a sequence of Selector objects
        /// </summary>
        /// <param name="selector"></param>
        /// <returns></returns>
        public Selector Parse(string selector)
        {
            Selectors = new Selector();

            string sel = (selector ?? String.Empty).Trim();

            if (IsHtml(selector))
            {
                Current.Html         = sel;
                Current.SelectorType = SelectorType.HTML;
                Selectors.Add(Current);
                return(Selectors);
            }

            scanner = Scanner.Create(sel);

            while (!scanner.Finished)
            {
                switch (scanner.Current)
                {
                case '*':
                    StartNewSelector(SelectorType.All);
                    scanner.Next();
                    break;

                case '<':
                    // not selecting - creating html
                    Current.Html = sel;
                    scanner.End();
                    break;

                case ':':
                    scanner.Next();
                    string key = scanner.Get(MatchFunctions.PseudoSelector).ToLower();
                    switch (key)
                    {
                    case "input":
                        AddTagSelector("input");
                        AddTagSelector("textarea", true);
                        AddTagSelector("select", true);
                        AddTagSelector("button", true);
                        break;

                    case "text":
                        StartNewSelector(SelectorType.AttributeValue | SelectorType.Tag);
                        Current.Tag = "input";
                        Current.AttributeSelectorType = AttributeSelectorType.Equals;
                        Current.AttributeName         = "type";
                        Current.AttributeValue        = "text";

                        StartNewSelector(SelectorType.AttributeValue | SelectorType.Tag, CombinatorType.Grouped, Current.TraversalType);
                        Current.Tag = "input";
                        Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                        Current.AttributeName         = "type";

                        Current.SelectorType |= SelectorType.Tag;
                        Current.Tag           = "input";
                        break;

                    case "checkbox":
                    case "radio":
                    case "button":
                    case "file":
                    case "image":
                    case "password":
                        AddInputSelector(key, "input");
                        break;

                    case "reset":
                    case "submit":
                        AddInputSelector(key);
                        break;

                    case "checked":
                    case "selected":
                    case "disabled":
                        StartNewSelector(SelectorType.AttributeValue);
                        Current.AttributeSelectorType = AttributeSelectorType.Exists;
                        Current.AttributeName         = key;
                        break;

                    case "enabled":
                        StartNewSelector(SelectorType.AttributeValue);
                        Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                        Current.AttributeName         = "disabled";
                        break;

                    case "first-letter":
                    case "first-line":
                    case "before":
                    case "after":
                        throw new NotImplementedException("The CSS pseudoelement selectors are not implemented in CsQuery.");

                    case "target":
                    case "link":
                    case "hover":
                    case "active":
                    case "focus":
                    case "visited":
                        throw new NotImplementedException("Pseudoclasses that require a browser aren't implemented.");

                    default:
                        if (!AddPseudoSelector(key))
                        {
                            throw new ArgumentException("Unknown pseudo-class :\"" + key + "\". If this is a valid CSS or jQuery selector, please let us know.");
                        }
                        break;
                    }
                    break;

                case '.':
                    StartNewSelector(SelectorType.Class);
                    scanner.Next();
                    Current.Class = scanner.Get(MatchFunctions.CssClassName);
                    break;

                case '#':

                    scanner.Next();
                    if (!scanner.Finished)
                    {
                        StartNewSelector(SelectorType.ID);
                        Current.ID = scanner.Get(MatchFunctions.HtmlIDValue());
                    }

                    break;

                case '[':
                    StartNewSelector(SelectorType.AttributeValue);

                    IStringScanner innerScanner = scanner.ExpectBoundedBy('[', true).ToNewScanner();

                    Current.AttributeName = innerScanner.Get(MatchFunctions.HTMLAttribute());
                    innerScanner.SkipWhitespace();

                    if (innerScanner.Finished)
                    {
                        Current.AttributeSelectorType = AttributeSelectorType.Exists;
                    }
                    else
                    {
                        string matchType = innerScanner.Get("=", "^=", "*=", "~=", "$=", "!=", "|=");

                        // CSS allows [attr=] as a synonym for [attr]
                        if (innerScanner.Finished)
                        {
                            Current.AttributeSelectorType = AttributeSelectorType.Exists;
                        }
                        else
                        {
                            var rawValue = innerScanner.Expect(expectsOptionallyQuotedValue()).ToNewScanner();

                            Current.AttributeValue = rawValue.Finished ?
                                                     "" :
                                                     rawValue.Get(new EscapedString());

                            switch (matchType)
                            {
                            case "=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.Equals;
                                break;

                            case "^=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.StartsWith;
                                // attributevalue starts with "" matches nothing
                                if (Current.AttributeValue == "")
                                {
                                    Current.AttributeValue = "" + (char)0;
                                }
                                break;

                            case "*=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.Contains;
                                break;

                            case "~=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.ContainsWord;
                                break;

                            case "$=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.EndsWith;
                                break;

                            case "!=":
                                Current.AttributeSelectorType = AttributeSelectorType.NotEquals;
                                // must matched manually - missing also validates as notEquals
                                break;

                            case "|=":
                                Current.SelectorType         |= SelectorType.AttributeValue;
                                Current.AttributeSelectorType = AttributeSelectorType.StartsWithOrHyphen;

                                break;

                            default:
                                throw new ArgumentException("Unknown attibute matching operator '" + matchType + "'");
                            }
                        }
                    }

                    break;

                case ',':
                    FinishSelector();
                    NextCombinatorType = CombinatorType.Root;
                    NextTraversalType  = TraversalType.All;
                    scanner.NextNonWhitespace();
                    break;

                case '+':
                    StartNewSelector(TraversalType.Adjacent);
                    scanner.NextNonWhitespace();
                    break;

                case '~':
                    StartNewSelector(TraversalType.Sibling);
                    scanner.NextNonWhitespace();
                    break;

                case '>':
                    StartNewSelector(TraversalType.Child);
                    // This is a wierd thing because if you use the > selector against a set directly, the meaning is "filter"
                    // whereas if it is used in a combination selector the meaning is "filter for 1st child"
                    //Current.ChildDepth = (Current.CombinatorType == CombinatorType.Root ? 0 : 1);
                    Current.ChildDepth = 1;
                    scanner.NextNonWhitespace();
                    break;

                case ' ':
                    // if a ">" or "," is later found, it will be overridden.
                    scanner.NextNonWhitespace();
                    NextTraversalType = TraversalType.Descendent;
                    break;

                default:

                    string tag = "";
                    if (scanner.TryGet(MatchFunctions.HTMLTagSelectorName(), out tag))
                    {
                        AddTagSelector(tag);
                    }
                    else
                    {
                        if (scanner.Index == 0)
                        {
                            Current.Html         = sel;
                            Current.SelectorType = SelectorType.HTML;
                            scanner.End();
                        }
                        else
                        {
                            throw new ArgumentException(scanner.LastError);
                        }
                    }

                    break;
                }
            }
            // Close any open selectors
            FinishSelector();
            if (Selectors.Count == 0)
            {
                var empty = new SelectorClause
                {
                    SelectorType  = SelectorType.None,
                    TraversalType = TraversalType.Filter
                };
                Selectors.Add(empty);
            }
            return(Selectors);
        }
Ejemplo n.º 9
0
        public IEnumerable<Selector> Parse(string selector)
        {
            Selectors = new List<Selector>();

            string sel = (selector ?? String.Empty).Trim();

            if (IsHtml(selector))
            {
                Current.Html = sel;
                Current.SelectorType = SelectorType.HTML;
                Selectors.Add(Current);
                return Selectors;
            }
            scanner = Scanner.Create(sel);

            while (!scanner.Finished)
            {
                switch (scanner.NextChar)
                {
                    case '*':
                        Current.SelectorType = SelectorType.All;
                        scanner.Next();
                        break;
                    case '<':
                        // not selecting - creating html
                        Current.Html = sel;
                        scanner.End();
                        break;
                    case ':':
                        scanner.Next();
                        string key = scanner.Get(MatchFunctions.PseudoSelector);
                        switch (key)
                        {
                            case "checkbox":
                            case "radio":
                            case "button":
                            case "file":
                            case "text":
                            case "password":
                                StartNewSelector(SelectorType.Attribute);

                                //Current.SelectorType |= SelectorType.Attribute;
                                Current.AttributeSelectorType = AttributeSelectorType.Equals;
                                Current.AttributeName = "type";
                                Current.AttributeValue = key;

                                if (key == "button" && !Current.SelectorType.HasFlag(SelectorType.Tag))
                                {
                                    //StartNewSelector(CombinatorType.Cumulative);
                                    StartNewSelector(SelectorType.Tag, CombinatorType.Cumulative, Current.TraversalType);
                                    //Current.SelectorType = SelectorType.Tag;
                                    Current.Tag = "button";
                                }
                                break;
                            case "checked":
                            case "selected":
                            case "disabled":
                                StartNewSelector(SelectorType.Attribute);
                                Current.AttributeSelectorType = AttributeSelectorType.Exists;
                                Current.AttributeName = key;
                                break;
                            case "enabled":
                                StartNewSelector(SelectorType.Attribute);
                                Current.AttributeSelectorType = AttributeSelectorType.NotExists;
                                Current.AttributeName = "disabled";
                                break;
                            case "contains":

                                StartNewSelector(SelectorType.Contains);
                                IStringScanner inner = scanner.ExpectBoundedBy('(', true).ToNewScanner();
                                Current.Criteria = inner.Get(MatchFunctions.OptionallyQuoted);
                                break;
                            case "eq":
                            case "gt":
                            case "lt":
                                StartNewSelector(SelectorType.Position);
                                switch (key)
                                {
                                    case "eq": Current.PositionType = PositionType.IndexEquals; break;
                                    case "lt": Current.PositionType = PositionType.IndexLessThan; break;
                                    case "gt": Current.PositionType = PositionType.IndexGreaterThan; break;
                                }

                                scanner.ExpectChar('(');
                                Current.PositionIndex = Convert.ToInt32(scanner.GetNumber());
                                scanner.ExpectChar(')');

                                break;
                            case "even":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.Even;
                                break;
                            case "odd":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.Odd;
                                break;
                            case "first":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.First;
                                break;
                            case "last":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.Last;
                                break;
                            case "last-child":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.LastChild;
                                break;
                            case "first-child":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.FirstChild;
                                break;
                            case "nth-child":
                                StartNewSelector(SelectorType.Position);
                                Current.PositionType = PositionType.NthChild;
                                Current.Criteria = scanner.GetBoundedBy('(');
                                break;
                            case "has":
                            case "not":
                                StartNewSelector(key == "has" ? SelectorType.SubSelectorHas : SelectorType.SubSelectorNot);
                                Current.TraversalType = TraversalType.Descendent;

                                string criteria = Current.Criteria = scanner.GetBoundedBy('(', true);
                                SelectorChain subSelectors = new SelectorChain(criteria);
                                Current.SubSelectors.Add(subSelectors);
                                break;
                            case "visible":
                                StartNewSelector(SelectorType.Other);
                                Current.OtherType = OtherType.Visible;
                                break;
                            default:
                                throw new ArgumentOutOfRangeException("Unknown pseudoselector :\"" + key + "\"");
                        }
                        break;
                    case '.':
                        StartNewSelector(SelectorType.Class);
                        scanner.Next();
                        Current.Class = scanner.Get(MatchFunctions.CssClass);
                        break;
                    case '#':

                        scanner.Next();
                        if (!scanner.Finished)
                        {
                            StartNewSelector(SelectorType.ID);
                            Current.ID = scanner.Get(MatchFunctions.HtmlIDValue);
                        }

                        break;
                    case '[':
                        StartNewSelector(SelectorType.Attribute);

                        IStringScanner innerScanner = scanner.ExpectBoundedBy('[', true).ToNewScanner();
                        Current.AttributeName = innerScanner.Get(MatchFunctions.HTMLAttribute);
                        innerScanner.SkipWhitespace();

                        if (innerScanner.Finished)
                        {
                            Current.AttributeSelectorType = AttributeSelectorType.Exists;
                        }
                        else
                        {
                            string matchType = innerScanner.Get("=", "^=", "*=", "~=", "$=", "!=");
                            Current.AttributeValue = innerScanner.Get(expectsOptionallyQuotedValue());
                            switch (matchType)
                            {

                                case "=":
                                    Current.AttributeSelectorType = AttributeSelectorType.Equals;
                                    break;
                                case "^=":
                                    Current.AttributeSelectorType = AttributeSelectorType.StartsWith;
                                    break;
                                case "*=":
                                    Current.AttributeSelectorType = AttributeSelectorType.Contains;
                                    break;
                                case "~=":
                                    Current.AttributeSelectorType = AttributeSelectorType.ContainsWord;
                                    break;
                                case "$=":
                                    Current.AttributeSelectorType = AttributeSelectorType.EndsWith;
                                    break;
                                case "!=":
                                    Current.AttributeSelectorType = AttributeSelectorType.NotEquals;
                                    break;
                                default:
                                    throw new ArgumentOutOfRangeException("Unknown attibute matching operator '" + matchType + "'");
                            }
                        }

                        break;
                    case ',':
                        FinishSelector();
                        scanner.NextNonWhitespace();
                        break;
                    case '>':
                        if (Current.IsComplete)
                        {
                            StartNewSelector(TraversalType.Child);
                        }
                        else
                        {
                            Current.TraversalType = TraversalType.Child;
                        }

                        // This is a wierd thing because if you use the > selector against a set directly, the meaning is "filter"
                        // whereas if it is used in a combination selector the meaning is "filter for 1st child"
                        Current.ChildDepth = (Current.CombinatorType == CombinatorType.Root ? 0 : 1);
                        scanner.NextNonWhitespace();
                        break;
                    case ' ':
                        // if a ">" or "," is later found, it will be overridden.
                        scanner.NextNonWhitespace();
                        StartNewSelector(TraversalType.Descendent);
                        break;
                    default:

                        string tag = "";
                        if (scanner.TryGet(MatchFunctions.HTMLTagName, out tag))
                        {
                            StartNewSelector(SelectorType.Tag);
                            Current.Tag = tag;
                        }
                        else
                        {
                            if (scanner.Pos == 0)
                            {
                                Current.Html = sel;
                                Current.SelectorType = SelectorType.HTML;
                                scanner.End();
                            }
                            else
                            {
                                throw new InvalidOperationException(scanner.LastError);
                            }

                        }

                        break;
                }
            }
            // Close any open selectors
            FinishSelector();
            return Selectors;
        }