Example #1
0
    /// <summary>
    /// Evaluate a single expression
    /// </summary>
    /// <param name="item">The current item</param>
    /// <param name="exp">The expression to evaluate</param>
    /// <returns>The outcome of the expression</returns>
    public static bool EvaluateSingleExpression(Context context, string exp)
    {
      // Clean the expression
      exp = exp.Trim();

      // substitute tokens
      exp = Parser.PerformSubstitution(context, exp);

      // Parse elements
      string[] elms = Parser.ParseFirstLevelGroups(exp, Constants.SubcommandEnter, Constants.SubcommandExit);

      // Validate the expression
      if (elms.Length != 1 && elms.Length != 2 && elms.Length != 3 && elms.Length != 5 && elms.Length != 7)
        throw new ExpressionException("Malformed expression");

      // a single element in the expression should be parsable true or false
      if (elms.Length == 1)
      {
        var value = false;
        if (Parser.TryParseBoolean(elms[0], out value))
          return value;
        else
          throw new ExpressionException("Could not parse boolean value '" + elms[0] + "'");
      }

      // 2 elements means a function
      if (elms.Length == 2)
      {
        switch (elms[0])
        {
          case "isempty":
            return string.IsNullOrEmpty(elms[1]);

          case "not":
            return !EvaluateExpression(context, elms[1]);

          case "isbound":
            return context.CommandHandler.CoreCommands.ContainsKey(elms[1]) || context.CommandHandler.CustomCommands.ContainsKey(elms[1]);

          default:
            throw new ExpressionException("Unknown function " + elms[0]);
        }
      }

      string op = elms[1];
      if ((op != "<") && (op != ">") && (op != "=") && (op != "!=") && (op != "<=") && (op != ">=") && (op != "[") && (op != "]") && (op != "?") && (op != "!?"))
        throw new ExpressionException("Invalid operator " + op);

      // substitute fields and attributes and pull out casting operator and flags
      string type = "string";
      bool ignoreCase = false;
      bool ignoreDecimal = false;
      bool round = false;
      bool ceil = false;
      bool floor = false;

      for (int i = 0; i < elms.Length; i++)
      {
        if (elms[i].StartsWith("@@"))
        {
          var inspector = new ItemInspector(context.CurrentItem);
          var attr = inspector.GetItemAttribute(elms[i]);
          if (attr == null)
            throw new ExpressionException("Unknown attribute " + elms[i]);

          elms[i] = attr;
        }
        else if (elms[i].StartsWith("@"))
        {
          elms[i] = context.CurrentItem[elms[i].Substring(1)];
        }
        else
        {
          if (elms[i] == "as")
          {
            if (elms.Length >= i + 2)
              type = elms[i + 1];
            else
              throw new ExpressionException("Missing the cast type");
          }
          else if (elms[i] == "with")
          {
            if (elms.Length < i + 2)
              throw new ExpressionException("Missing flags");

            switch (elms[i + 1])
            {
              case "ignorecase": ignoreCase = true; break;
              case "ignoredecimal": ignoreDecimal = true; break;
              case "round": round = true; break;
              case "ceiling": ceil = true; break;
              case "floor": floor = true; break;
              default:
                throw new ExpressionException("Unknown flag " + elms[i + 1]);
            }
          }
        }
      }

      string val1 = elms[0];
      string val2 = elms[2];

      // Do we need to convert the strings?
      switch (type)
      {
        case "string":
          if (ignoreCase)
          {
            val1 = val1.ToLower();
            val2 = val2.ToLower();
          }

          // Now do the comparison
          switch (op)
          {
            case "=":
              return val1 == val2;

            case "<":
              return string.Compare(val1, val2) < 0;

            case ">":
              return string.Compare(val1, val2) > 0;

            case "!=":
              return val1 != val2;

            case "<=":
              return string.Compare(val1, val2) <= 0;

            case ">=":
              return string.Compare(val1, val2) >= 0;

            case "[":
              return val1.StartsWith(val2);

            case "]":
              return val1.EndsWith(val2);

            case "?":
              return val1.Contains(val2);

            case "!?":
              return !val1.Contains(val2);
          }
          break;

        case "number":
          if (val1.Length == 0 || val2.Length == 0)
            return false;

          double a = 0;
          double b = 0;
          if (!double.TryParse(val1, out a))
            throw new ExpressionException(string.Format("{0} is not a number", val1));
          if (!double.TryParse(val2, out b))
            throw new ExpressionException(string.Format("{0} is not a number", val2));

          if (ignoreDecimal)
          {
            a = Math.Truncate(a);
            b = Math.Truncate(b);
          }

          if (ceil)
          {
            a = Math.Ceiling(a);
            b = Math.Ceiling(b);
          }

          if (floor)
          {
            a = Math.Floor(a);
            b = Math.Floor(b);
          }

          if (round)
          {
            a = Math.Round(a);
            b = Math.Round(b);
          }

          // Now do the comparison
          switch (op)
          {
            case "=":
              return a == b;

            case "<":
              return a < b;

            case ">":
              return a > b;

            case "!=":
              return a != b;

            case "<=":
              return a <= b;

            case ">=":
              return a >= b;

            case "[":
              return a.ToString().StartsWith(b.ToString());

            case "]":
              return a.ToString().EndsWith(b.ToString());

            case "?":
              return a.ToString().Contains(b.ToString());

            case "!?":
              return !a.ToString().Contains(b.ToString());
          }
          break;

        case "date":
          if (val1.Length == 0 || val2.Length == 0)
            return false;

          DateTime aa;
          DateTime bb;
          DateTime defaultPassthrough = DateTime.MinValue.AddSeconds(7);

          var culture = Sitecore.Context.Culture;
          if (culture.IsNeutralCulture)
            culture = Thread.CurrentThread.CurrentCulture;

          aa = Sitecore.DateUtil.ParseDateTime(val1, defaultPassthrough, culture);
          if (aa == defaultPassthrough)
            throw new ExpressionException(string.Format("{0} is not a date", val1));

          bb = Sitecore.DateUtil.ParseDateTime(val2, defaultPassthrough, culture);
          if (bb == defaultPassthrough)
            throw new ExpressionException(string.Format("{0} is not a date", val2));

          // Now do the comparison
          switch (op)
          {
            case "=":
              return aa == bb;

            case "<":
              return aa < bb;

            case ">":
              return aa > bb;

            case "!=":
              return aa != bb;

            case "<=":
              return aa <= bb;

            case ">=":
              return aa >= bb;
          }
          break;
      }

      // Something went wrong if we get to here
      return false;
    }
Example #2
0
 public static string GetItemAttribute(Item item, string name)
 {
   var inspector = new ItemInspector(item);
   return inspector.GetItemAttribute(name);
 }