// :not(selector) private void Not() { tq.Consume(":not"); string subQuery = tq.ChompBalanced('(', ')'); if (subQuery.Length == 0) { throw DomFailure.NotSelectorSelectionCannotBeEmpty(); } evals.Add(new StructuralEvaluator.Not(Parse(subQuery, _options))); }
// pseudo selector :has(el) private void Has() { tq.Consume(":has"); string subQuery = tq.ChompBalanced('(', ')'); // TODO Validation errors in a structured way if (subQuery.Length == 0) { throw DomFailure.HasSelectorCannotBeEmpty(); } evals.Add(new StructuralEvaluator.Has(Parse(subQuery, _options))); }
public void Unwrap_cannot_unwrap_root_with_multiple_children() { DomDocument doc = new DomDocument(); var e = doc.AppendElement("t"); var firstChild = e.AppendElement("u"); var secondChild = e.AppendElement("u"); var ex = Record.Exception(() => e.Unwrap()); Assert.IsInstanceOf <InvalidOperationException>(ex); Assert.Equal(DomFailure.CannotUnwrapWouldCreateMalformedDocument().Message, ex.Message); }
private Evaluator Contains(bool own, string tq) { string searchText = TokenQueue.Unescape(tq); if (searchText.Length == 0) { throw DomFailure.ContainsSelectorCannotBeEmpty(); } if (own) { return(new Evaluator.ContainsOwnText(searchText)); } return(new Evaluator.ContainsText(searchText)); }
private Evaluator Matches(bool own, string tq) { string regex = tq; if (string.IsNullOrEmpty(regex)) { throw DomFailure.MatchesSelectorCannotBeEmpty(); } if (own) { return(new Evaluator.MatchesOwn(new Regex(regex))); } return(new Evaluator.MatchesImpl(new Regex(regex))); }
public void Consume(string seq) { if (!Matches(seq)) { throw DomFailure.QueueDidNotMatch(); } int len = seq.Length; if (len > RemainingLength) { throw DomFailure.QueueNotLongEnoughToConsumeSequence(); } pos += len; }
private void FindElements() { if (tq.MatchChomp("#")) { ById(); return; } if (tq.MatchChomp(".")) { ByClass(); return; } if (tq.MatchesWord()) { ByTag(); return; } if (tq.Matches("[")) { ByAttribute(); return; } if (tq.MatchChomp("*")) { AllElements(); return; } if (tq.Matches(":not(")) { Not(); return; } if (tq.Matches(":has(")) { Has(); return; } foreach (var exp in _options.Expressions) { if (!tq.Matches(exp.MatchToken)) { continue; } if (exp.HasArguments) { tq.Consume(exp.Token); string cq = tq.ChompBalanced('(', ')'); var eval = exp.CreateEvaluator(cq); evals.Add(eval); return; } else { throw new NotImplementedException(); } } // unhandled throw DomFailure.CouldNotParseQuery(query, tq.Remainder()); }
private void Combinator(char combinator) { tq.ConsumeWhitespace(); string subQuery = ConsumeSubQuery(); // support multi > childs Evaluator rootEval; // the new topmost evaluator Evaluator currentEval; // the evaluator the new eval will be combined to. could be root, or rightmost or. Evaluator newEval = Parse(subQuery, _options); // the evaluator to add into target evaluator bool replaceRightMost = false; if (evals.Count == 1) { rootEval = currentEval = evals[0]; // make sure OR (,) has precedence: if (rootEval is CombiningEvaluator.Or && combinator != ',') { currentEval = ((CombiningEvaluator.Or)currentEval).RightMostEvaluator(); replaceRightMost = true; } } else { rootEval = currentEval = new CombiningEvaluator.And(evals); } evals.Clear(); // for most combinators: change the current eval into an AND of the current eval and the new eval switch (combinator) { case '>': currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.ImmediateParent(currentEval)); break; case ' ': currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.Parent(currentEval)); break; case '+': currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.ImmediatePreviousSibling(currentEval)); break; case '~': currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.PreviousSibling(currentEval)); break; case ',': // group or. CombiningEvaluator.Or or = currentEval as CombiningEvaluator.Or; if (or != null) { or.Add(newEval); } else { or = new CombiningEvaluator.Or(); or.Add(currentEval); or.Add(newEval); } currentEval = or; break; default: throw DomFailure.UnknownCombinator(combinator); } if (replaceRightMost) { ((CombiningEvaluator.Or)rootEval).ReplaceRightMostEvaluator(currentEval); } else { rootEval = currentEval; } evals.Add(rootEval); }