Пример #1
0
        private static JToken Transform(JToken input, JsonTransformerContext context)
        {
            if (context.ReservedProperties.Data is JArray dataArray)
            {
                if (!context.ParentIsArray)
                {
                    // If we can't repeat, we select the first item in the array
                    context.Warnings.AddWarning("Current data is an array, but parent item isn't an array. Selecting the first item for current data.");
                    context.ReservedProperties.Data = dataArray.FirstOrDefault();
                }
            }

            switch (input.Type)
            {
            case JTokenType.Array:
                return(TransformArray(input as JArray, new JsonTransformerContext(context)));

            case JTokenType.String:
                return(JsonStringTransformer.Transform(input.Value <string>(), new JsonTransformerContext(context)));

            case JTokenType.Object:
                return(TransformObject(input as JObject, new JsonTransformerContext(context)).FirstOrDefault());
            }

            return(input.DeepClone());
        }
Пример #2
0
        private static JArray TransformArray(JArray inputArray, JsonTransformerContext context)
        {
            var newArray = new JArray();

            foreach (var child in inputArray)
            {
                if (child is JObject childObj)
                {
                    var newChildren = TransformObject(childObj, new JsonTransformerContext(context)
                    {
                        ParentIsArray = true
                    });
                    foreach (var newChild in newChildren)
                    {
                        newArray.Add(newChild);
                    }
                }
                else
                {
                    var newChild = Transform(child, new JsonTransformerContext(context)
                    {
                        ParentIsArray = true
                    });
                    if (newChild != null)
                    {
                        newArray.Add(newChild);
                    }
                }
            }
            return(newArray);
        }
Пример #3
0
        /// <summary>
        /// Evaluates a simple object expression, like "reportsTo.name" or "people[0].name" or even "'Andrew'" or "4"
        /// </summary>
        /// <param name="objectExpression"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        private static JToken EvaluateObjectExpression(string objectExpression, JsonTransformerContext context)
        {
            Match firstPropertyMatch = Regex.Match(objectExpression, "^" + REGEX_PROPERTY_NAME);

            if (firstPropertyMatch.Success)
            {
                string remainingToParse = objectExpression;
                JToken data;
                if (firstPropertyMatch.Value.StartsWith("$"))
                {
                    data = context.ReservedProperties.GetValue(firstPropertyMatch.Value.Substring(1));
                    if (data == null)
                    {
                        return(null);
                    }

                    remainingToParse = remainingToParse.Substring(firstPropertyMatch.Length);
                }
                else
                {
                    remainingToParse = "." + remainingToParse;
                    data             = context.ReservedProperties.Data;
                }

                if (remainingToParse.Length > 0)
                {
                    data = EvaluateAccessorExpression(remainingToParse, data, context);
                }

                return(data);
            }

            return(null);
        }
Пример #4
0
        public JsonTransformerContext(JsonTransformerContext existingContext)
        {
            foreach (var p in this.GetType().GetTypeInfo().DeclaredProperties)
            {
                p.SetValue(this, p.GetValue(existingContext));
            }

            if (Types != null)
            {
                Types = Types.Clone();
            }

            if (ReservedProperties != null)
            {
                ReservedProperties = new JsonTransformerReservedProperties(ReservedProperties);
            }
        }
Пример #5
0
        private static List <JObject> TransformObject(JObject input, JsonTransformerContext context)
        {
            List <JObject> answer = new List <JObject>();

            // Clone it since we'll be modifying it
            input = input.DeepClone() as JObject;

            // If new custom types are declared
            if (input.TryGetValue(PROP_TYPES, out JToken typesAsToken))
            {
                input.Remove(PROP_TYPES);
                try
                {
                    // We need to obtain them before applying data binding
                    var newTypes = typesAsToken.ToObject <JsonTransformerTypes>();
                    if (newTypes != null)
                    {
                        context.Types = context.Types.Merge(newTypes);
                    }
                }
                catch { }
            }

            // If data is specified
            if (input.TryGetValue(PROP_DATA, out JToken dataVal))
            {
                // Remove the data property
                input.Remove(PROP_DATA);

                // Transform and use the data
                context.ReservedProperties.Data = Transform(dataVal, new JsonTransformerContext(context)
                {
                    ParentIsArray = false
                });

                // If we couldn't find the data, we drop the entire element
                if (context.ReservedProperties.Data == null)
                {
                    return(answer);
                }
            }
            else
            {
                // Otherwise, inherit parent's data
            }

            // If current data is an array
            if (context.ReservedProperties.Data != null && context.ReservedProperties.Data is JArray array)
            {
                // If our parent is an array type, we repeat
                if (context.ParentIsArray)
                {
                    int i = 0;
                    foreach (var dataItem in array)
                    {
                        JObject newRepeatedItem = input.DeepClone() as JObject;
                        newRepeatedItem.Remove(PROP_DATA);

                        foreach (var transformed in TransformObject(newRepeatedItem, new JsonTransformerContext(context)
                        {
                            ReservedProperties = new JsonTransformerReservedProperties(context.ReservedProperties)
                            {
                                Data = dataItem,
                                Index = i
                            }
                        }))
                        {
                            answer.Add(transformed);
                        }
                        i++;
                    }
                    return(answer);
                }
                else
                {
                    context.Warnings.AddWarning("Data was an array on item that isn't a child of an array. Selecting first item of data array.");
                    context.ReservedProperties.Data = array.FirstOrDefault();
                }
            }

            // Evaluate when clause
            if (input.TryGetValue(PROP_WHEN, out JToken whenToken))
            {
                input.Remove(PROP_WHEN);

                var transformedWhenValue = Transform(whenToken, new JsonTransformerContext(context)
                {
                    ParentIsArray = false
                });

                // If it evaluated to true
                if (transformedWhenValue != null && transformedWhenValue.Type == JTokenType.Boolean && transformedWhenValue.Value <bool>())
                {
                    // Keep it
                }
                else
                {
                    // Otherwise, drop it
                    return(answer);
                }
            }

            var newItem = new JObject();

            // Transform each property value
            foreach (var p in input.Properties().ToArray())
            {
                var transformedPropertyValue = Transform(p.Value, new JsonTransformerContext(context)
                {
                    ParentIsArray = false
                });
                if (transformedPropertyValue != null)
                {
                    newItem.Add(p.Name, transformedPropertyValue);
                }
            }

            // If custom type
            if (newItem.TryGetValue(PROP_TYPE, out JToken typeToken) && typeToken.Type == JTokenType.String)
            {
                var typeString = typeToken.Value <string>();
                if (context.Types.TryGetDefinition(typeString, out JToken definition) && definition is JObject definitionObj)
                {
                    foreach (var newTransformedItem in TransformObject(definitionObj, new JsonTransformerContext(context)
                    {
                        ReservedProperties = new JsonTransformerReservedProperties(context.ReservedProperties)
                        {
                            Props = newItem
                        }
                    }))
                    {
                        answer.Add(newTransformedItem);
                    }
                    return(answer);
                }
            }

            answer.Add(newItem);
            return(answer);
        }
Пример #6
0
        public static JToken EvaluateBinding(string bindingExpression, JsonTransformerContext context)
        {
            string remainingBindingExpression = bindingExpression;
            string answer = "";
            bool   first  = true;
            bool   found  = false;

            while (true)
            {
                int startIndex = remainingBindingExpression.IndexOf('{');
                if (startIndex != -1)
                {
                    string substr      = remainingBindingExpression.Substring(startIndex);
                    var    inputStream = new AntlrInputStream(substr);
                    var    lexer       = new BindingExpressionsLexer(inputStream);
                    var    tokenStream = new CommonTokenStream(lexer);
                    var    parser      = new BindingExpressionsParser(tokenStream);
                    parser.AddErrorListener(new ErrorListener());

                    var foundExpression = parser.bindingExpression();

                    // If it actually found something
                    if (foundExpression.Stop.StopIndex < substr.Length && parser.NumberOfSyntaxErrors == 0)
                    {
                        var    visitor = new BindingExpressionsVisitor(context);
                        JToken result  = visitor.Visit(foundExpression);

                        answer += remainingBindingExpression.Substring(0, startIndex);
                        answer += result;

                        remainingBindingExpression = substr;
                        remainingBindingExpression = remainingBindingExpression.Substring(foundExpression.Stop.StopIndex + 1);

                        // If whole expression was the binding expression, don't do any string concatenation
                        if (first && startIndex == 0 && remainingBindingExpression.Length == 0)
                        {
                            return(result);
                        }

                        found = true;
                    }

                    else
                    {
                        // Otherwise, increment past there and try again
                        answer += remainingBindingExpression.Substring(startIndex + 1);
                        remainingBindingExpression = remainingBindingExpression.Substring(startIndex + 1);
                    }
                }
                else
                {
                    answer += remainingBindingExpression;
                    break;
                }

                first = false;
            }

            if (found)
            {
                return(answer);
            }

            return(bindingExpression);

            //var inputStream = new AntlrInputStream(bindingExpression);
            //var lexer = new BindingExpressionsLexer(inputStream);
            //var tokenStream = new CommonTokenStream(lexer);
            //var parser = new BindingExpressionsParser(tokenStream);

            //var foundExpression = parser.input_string();
            //if (foundExpression.IsEmpty)
            //{
            //    //return bindingExpression;
            //}
            //var visitor = new BindingExpressionsVisitor(context);
            //JToken result = visitor.Visit(foundExpression);
            //return result;


            // If it's all one single expression, we don't do any string concatenation and we return the actual type
            var match = Regex.Match(bindingExpression, "^" + REGEX_BINDING_EXPRESSION + "$");

            if (match.Success && match.Groups[1].Success)
            {
                return(EvaluateComplexExpression(match.Groups[1].Value, context));
            }

            Regex regex     = new Regex(REGEX_BINDING_EXPRESSION);
            var   evaluator = new MyMatchEvaluator(context);

            string replaced = regex.Replace(bindingExpression, evaluator.ReplaceBinding);

            return(replaced);
        }
Пример #7
0
        /// <summary>
        /// Evaluates full property accessor expressions, like ".person.name" or ".person['First Name']", etc
        /// </summary>
        /// <param name="data"></param>
        /// <param name="propertyExpression"></param>
        /// <returns></returns>
        public static JToken EvaluateAccessorExpression(string propertyExpression, JToken currData, JsonTransformerContext context)
        {
            if (currData == null)
            {
                return(null);
            }

            JToken nextData    = null;
            string matchedText = null;

            Regex regex = new Regex("^" + REGEX_PROPERTY_ACCESSOR);
            var   matchPropertyAccessor = regex.Match(propertyExpression);

            if (matchPropertyAccessor.Success && matchPropertyAccessor.Groups[1].Success)
            {
                string property = matchPropertyAccessor.Groups[1].Value;
                nextData    = GetProperty(currData, property);
                matchedText = matchPropertyAccessor.Value;
            }
            else
            {
                regex = new Regex("^" + REGEX_DICTIONARY_LOOKUP);
                var matchDictionary = regex.Match(propertyExpression);
                if (matchDictionary.Success && matchDictionary.Groups[1].Success)
                {
                    string dictionaryAccessor = matchDictionary.Groups[1].Value;
                    nextData    = GetProperty(currData, dictionaryAccessor);
                    matchedText = matchDictionary.Value;
                }
                else
                {
                    regex = new Regex("^" + REGEX_INDEX_ACCESSOR);
                    var matchIndex = regex.Match(propertyExpression);
                    if (matchIndex.Success && matchIndex.Groups[1].Success && int.TryParse(matchIndex.Groups[1].Value, out int indexToAccess))
                    {
                        nextData    = currData.ElementAtOrDefault(indexToAccess);
                        matchedText = matchIndex.Value;
                    }
                }
            }

            if (nextData != null)
            {
                if (matchedText.Length < propertyExpression.Length)
                {
                    return(EvaluateAccessorExpression(propertyExpression.Substring(matchedText.Length), nextData, context));
                }
                else
                {
                    return(nextData);
                }
            }

            return(null);
        }
Пример #8
0
 public MyMatchEvaluator(JsonTransformerContext context)
 {
     _context = context;
 }
Пример #9
0
 internal static JToken Transform(string input, JsonTransformerContext context)
 {
     return(EvaluateBinding(input, context));
 }
Пример #10
0
        /// <summary>
        /// A complex expression, like "person.name", "person['details'].name", "name == 'Andrew'", or even nested complex expressions
        /// </summary>
        /// <param name="complexExpression"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static JToken EvaluateComplexExpression(string complexExpression, JsonTransformerContext context)
        {
            var complexMatch = Regex.Match(complexExpression, "^" + REGEX_COMPLEX_EXPRESSION + "$");

            if (complexMatch.Success)
            {
            }

            Match firstPropertyMatch = Regex.Match(complexExpression, "^" + REGEX_PROPERTY_NAME);

            if (firstPropertyMatch.Success)
            {
                string remainingToParse = complexExpression;
                JToken data;
                if (firstPropertyMatch.Value.StartsWith("$"))
                {
                    data = context.ReservedProperties.GetValue(firstPropertyMatch.Value.Substring(1));
                    if (data == null)
                    {
                        return(null);
                    }

                    remainingToParse = remainingToParse.Substring(firstPropertyMatch.Length);
                }
                else
                {
                    remainingToParse = "." + remainingToParse;
                    data             = context.ReservedProperties.Data;
                }

                if (remainingToParse.Length > 0)
                {
                    data = EvaluateAccessorExpression(remainingToParse, data, context);
                }

                string remainingExpression = complexExpression.Substring(firstPropertyMatch.Value.Length);

                // See if there's a binary operator following this object
                var regexOperator = new Regex("^" + REGEX_OPERATOR);
                var matchOperator = regexOperator.Match(remainingExpression);
                if (matchOperator.Success && matchOperator.Groups[1].Success)
                {
                    string operatorStr = matchOperator.Groups[1].Value;

                    // Get the second object of the binary operation
                    // Note this is slightly incorrect, since it'll join chained operations from the end to the front. For example,
                    // true == 'Andrew' == 'Andrew' would evaluate to true, as (true == ('Andrew' == 'Andrew')), but it should be the other way around
                    // Plus I'm temporarily hacking this by appending { at the start, need to split this out into different methods better
                    JToken secondObject = EvaluateComplexExpression("{" + remainingExpression.Substring(matchOperator.Value.Length), context);

                    switch (operatorStr)
                    {
                    case "==":
                        return(object.Equals(data, secondObject));
                    }
                }

                return(data);
            }

            return(null);
        }