private static object ParseFunction(string functionString, string inputJson, JArray array, JToken currentArrayElement, JUSTContext localContext) { try { object output; string functionName, argumentString; if (!ExpressionHelper.TryParseFunctionNameAndArguments(functionString, out functionName, out argumentString)) { return(functionName); } string[] arguments = ExpressionHelper.GetArguments(argumentString); var listParameters = new List <object>(); if (functionName == "ifcondition") { var condition = ParseArgument(inputJson, array, currentArrayElement, arguments[0], localContext); var value = ParseArgument(inputJson, array, currentArrayElement, arguments[1], localContext); var index = condition.ToString().ToLower() == value.ToString().ToLower() ? 2 : 3; output = ParseArgument(inputJson, array, currentArrayElement, arguments[index], localContext); } else { int i = 0; for (; i < (arguments?.Length ?? 0); i++) { listParameters.Add(ParseArgument(inputJson, array, currentArrayElement, arguments[i], localContext)); } listParameters.Add(localContext ?? GlobalContext); var parameters = listParameters.ToArray(); if (new[] { "currentvalue", "currentindex", "lastindex", "lastvalue" }.Contains(functionName)) { output = ReflectionHelper.caller(null, "JUST.Transformer", functionName, new object[] { array, currentArrayElement }, true, localContext ?? GlobalContext); } else if (new[] { "currentvalueatpath", "lastvalueatpath" }.Contains(functionName)) { output = ReflectionHelper.caller(null, "JUST.Transformer", functionName, new object[] { array, currentArrayElement, parameters[0] }, true, localContext ?? GlobalContext); } else if (functionName == "currentproperty") { output = ReflectionHelper.caller(null, "JUST.Transformer", functionName, new object[] { array, currentArrayElement, localContext ?? GlobalContext }, false, localContext ?? GlobalContext); } else if (functionName == "customfunction") { output = CallCustomFunction(parameters, localContext); } else if (localContext?.IsRegisteredCustomFunction(functionName) ?? false) { var methodInfo = localContext.GetCustomMethod(functionName); output = ReflectionHelper.InvokeCustomMethod(methodInfo, parameters, true, localContext ?? GlobalContext); } else if (GlobalContext.IsRegisteredCustomFunction(functionName)) { var methodInfo = GlobalContext.GetCustomMethod(functionName); output = ReflectionHelper.InvokeCustomMethod(methodInfo, parameters, true, localContext ?? GlobalContext); } else if (Regex.IsMatch(functionName, ReflectionHelper.EXTERNAL_ASSEMBLY_REGEX)) { output = ReflectionHelper.CallExternalAssembly(functionName, parameters, localContext ?? GlobalContext); } else if (new[] { "xconcat", "xadd", "mathequals", "mathgreaterthan", "mathlessthan", "mathgreaterthanorequalto", "mathlessthanorequalto", "stringcontains", "stringequals" }.Contains(functionName)) { object[] oParams = new object[1]; oParams[0] = parameters; output = ReflectionHelper.caller(null, "JUST.Transformer", functionName, oParams, true, localContext ?? GlobalContext); } else if (functionName == "applyover") { var contextInput = GetInputToken(localContext); var input = JToken.Parse(Transform(parameters[0].ToString(), contextInput.ToString(), localContext)); (localContext ?? GlobalContext).Input = input; output = ParseFunction(parameters[1].ToString().Trim('\''), inputJson, array, currentArrayElement, localContext ?? GlobalContext); (localContext ?? GlobalContext).Input = contextInput; } else { var input = ((JUSTContext)parameters.Last()).Input; if (currentArrayElement != null && functionName != "valueof") { ((JUSTContext)parameters.Last()).Input = currentArrayElement; } output = ReflectionHelper.caller(null, "JUST.Transformer", functionName, parameters, true, localContext ?? GlobalContext); ((JUSTContext)parameters.Last()).Input = input; } } return(output); } catch (Exception ex) { throw new Exception("Error while calling function : " + functionString + " - " + ex.Message, ex); } }
private static void RecursiveEvaluate(JToken parentToken, string inputJson, JArray parentArray, JToken currentArrayToken, JUSTContext localContext) { if (parentToken == null) { return; } JEnumerable <JToken> tokens = parentToken.Children(); List <JToken> selectedTokens = null; Dictionary <string, JToken> tokensToReplace = null; List <JToken> tokensToDelete = null; List <string> loopProperties = null; JArray arrayToForm = null; JObject dictToForm = null; List <JToken> tokenToForm = null; List <JToken> tokensToAdd = null; bool isLoop = false; bool isBulk = false; foreach (JToken childToken in tokens) { if (childToken.Type == JTokenType.Array && (parentToken as JProperty)?.Name.Trim() != "#") { JArray arrayToken = childToken as JArray; List <object> itemsToAdd = new List <object>(); foreach (JToken arrEl in childToken.Children()) { object itemToAdd = arrEl.Value <JToken>(); if (arrEl.Type == JTokenType.String && arrEl.ToString().Trim().StartsWith("#")) { object value = ParseFunction(arrEl.ToString(), inputJson, parentArray, currentArrayToken, localContext); itemToAdd = value; } itemsToAdd.Add(itemToAdd); } arrayToken.RemoveAll(); foreach (object itemToAdd in itemsToAdd) { if (itemToAdd is Array) { foreach (var item in itemToAdd as Array) { arrayToken.Add(Utilities.GetNestedData(item)); } } else { arrayToken.Add(JToken.FromObject(itemToAdd)); } } } if (childToken.Type == JTokenType.Property) { JProperty property = childToken as JProperty; if (property.Name != null && property.Name == "#" && property.Value.Type == JTokenType.Array) { JArray values = property.Value as JArray; JEnumerable <JToken> arrayValues = values.Children(); foreach (JToken arrayValue in arrayValues) { if (arrayValue.Type == JTokenType.String && ExpressionHelper.TryParseFunctionNameAndArguments( arrayValue.Value <string>().Trim(), out string functionName, out string arguments)) { if (functionName == "copy") { if (selectedTokens == null) { selectedTokens = new List <JToken>(); } selectedTokens.Add(Copy(arguments, inputJson, parentArray, currentArrayToken, localContext)); } else if (functionName == "replace") { if (tokensToReplace == null) { tokensToReplace = new Dictionary <string, JToken>(); } var replaceResult = Replace(arguments, inputJson, parentArray, currentArrayToken, localContext); tokensToReplace.Add(replaceResult.Key, replaceResult.Value); } else if (functionName == "delete") { if (tokensToDelete == null) { tokensToDelete = new List <JToken>(); } tokensToDelete.Add(Delete(arguments, inputJson, parentArray, currentArrayToken, localContext)); } } } isBulk = true; } if (property.Name != null && property.Value.ToString().Trim().StartsWith("#") && !property.Name.Contains("#eval") && !property.Name.Contains("#ifgroup") && !property.Name.Contains("#loop")) { object newValue = ParseFunction(property.Value.ToString(), inputJson, parentArray, currentArrayToken, localContext); property.Value = GetToken(newValue, localContext); } /* For looping*/ isLoop = false; if (property.Name != null && property.Name.Contains("#eval")) { ExpressionHelper.TryParseFunctionNameAndArguments(property.Name, out string functionName, out string functionString); object functionResult = ParseFunction(functionString, inputJson, parentArray, currentArrayToken, localContext); JProperty clonedProperty = new JProperty(functionResult.ToString(), ParseFunction(property.Value.ToString(), inputJson, parentArray, currentArrayToken, localContext)); if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); if (tokensToAdd == null) { tokensToAdd = new List <JToken> { clonedProperty }; } } if (property.Name != null && property.Name.Contains("#ifgroup")) { ExpressionHelper.TryParseFunctionNameAndArguments(property.Name, out string functionName, out string functionString); object functionResult = ParseFunction(functionString, inputJson, parentArray, currentArrayToken, localContext); bool result = false; try { result = (bool)ReflectionHelper.GetTypedValue(typeof(bool), functionResult, GetEvaluationMode(localContext)); } catch { if (IsStrictMode(localContext)) { throw; } result = false; } if (result == true) { if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); RecursiveEvaluate(childToken, inputJson, parentArray, currentArrayToken, localContext); if (tokenToForm == null) { tokenToForm = new List <JToken>(); } foreach (JToken grandChildToken in childToken.Children()) { tokenToForm.Add(grandChildToken.DeepClone()); } } else { if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); } isLoop = true; } if (property.Name != null && property.Name.Contains("#loop")) { ExpressionHelper.TryParseFunctionNameAndArguments(property.Name, out string functionName, out string arguments); var token = currentArrayToken != null && functionName == "loopwithincontext" ? currentArrayToken : GetInputToken(localContext); var strArrayToken = ParseArgument(inputJson, parentArray, currentArrayToken, arguments, localContext) as string; bool isDictionary = false; JToken arrayToken; try { arrayToken = token.SelectToken(strArrayToken); if (Regex.IsMatch(strArrayToken ?? string.Empty, "\\[.+\\]$") && arrayToken.Type != JTokenType.Array) { arrayToken = new JArray(arrayToken); } if (arrayToken is IDictionary <string, JToken> dict) //JObject is a dictionary { isDictionary = true; JArray arr = new JArray(); foreach (var item in dict) { arr.Add(new JObject { { item.Key, item.Value } }); } arrayToken = arr; } } catch { var multipleTokens = token.SelectTokens(strArrayToken); arrayToken = new JArray(multipleTokens); } JArray array = arrayToken as JArray; if (array != null) { using (IEnumerator <JToken> elements = array.GetEnumerator()) { arrayToForm = new JArray(); if (!isDictionary) { while (elements.MoveNext()) { JToken clonedToken = childToken.DeepClone(); RecursiveEvaluate(clonedToken, inputJson, array, elements.Current, localContext); foreach (JToken replacedProperty in clonedToken.Children()) { arrayToForm.Add(replacedProperty); } } } else { dictToForm = new JObject(); while (elements.MoveNext()) { JToken clonedToken = childToken.DeepClone(); RecursiveEvaluate(clonedToken, inputJson, array, elements.Current, localContext); foreach (JToken replacedProperty in clonedToken.Children().Select(t => t.First)) { dictToForm.Add(replacedProperty); } } } } } if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); isLoop = true; } /*End looping */ } if (childToken.Type == JTokenType.String && childToken.Value <string>().Trim().StartsWith("#") && parentArray != null && currentArrayToken != null) { object newValue = ParseFunction(childToken.Value <string>(), inputJson, parentArray, currentArrayToken, localContext); JToken replaceToken = GetToken(newValue, localContext); childToken.Replace(replaceToken); } if (!isLoop && !isBulk) { RecursiveEvaluate(childToken, inputJson, parentArray, currentArrayToken, localContext); } } if (selectedTokens != null) { foreach (JToken selectedToken in selectedTokens) { if (selectedToken != null) { JEnumerable <JToken> copyChildren = selectedToken.Children(); foreach (JToken copyChild in copyChildren) { JProperty property = copyChild as JProperty; (parentToken as JObject).Add(property.Name, property.Value); } } } } if (tokensToReplace != null) { foreach (KeyValuePair <string, JToken> tokenToReplace in tokensToReplace) { JToken selectedToken = (parentToken as JObject).SelectToken(tokenToReplace.Key); selectedToken.Replace(tokenToReplace.Value); } } if (tokensToDelete != null) { foreach (string selectedToken in tokensToDelete) { JToken tokenToRemove = parentToken.SelectToken(selectedToken); if (tokenToRemove != null) { tokenToRemove.Ancestors().First().Remove(); } } } if (tokensToAdd != null) { foreach (JToken token in tokensToAdd) { (parentToken as JObject).Add((token as JProperty).Name, (token as JProperty).Value); } } if (tokenToForm != null) { foreach (JToken token in tokenToForm) { foreach (JProperty childToken in token.Children()) { (parentToken as JObject).Add(childToken.Name, childToken.Value); } } } if (parentToken is JObject jObject) { jObject.Remove("#"); } if (loopProperties != null) { foreach (string propertyToDelete in loopProperties) { if (dictToForm == null && arrayToForm == null && parentToken.Count() <= 1) { parentToken.Replace(JValue.CreateNull()); } else { (parentToken as JObject).Remove(propertyToDelete); } } } if (dictToForm != null) { parentToken.Replace(dictToForm); } else if (arrayToForm != null) { if (parentToken.Parent != null && parentToken.Parent is JArray arr) { foreach (var item in arrayToForm) { arr.Add(item); } if (!parentToken.HasValues) { var tmp = parentToken; parentToken = arr; tmp.Remove(); } } else if (parentToken.Parent != null) { parentToken.Replace(arrayToForm); } } }
private static void RecursiveEvaluate(JToken parentToken, string inputJson, JArray parentArray, JToken currentArrayToken, JUSTContext localContext) { if (parentToken == null) { return; } JEnumerable <JToken> tokens = parentToken.Children(); List <JToken> selectedTokens = null; Dictionary <string, JToken> tokensToReplace = null; List <JToken> tokensToDelete = null; List <string> loopProperties = null; JArray arrayToForm = null; List <JToken> tokenToForm = null; List <JToken> tokensToAdd = null; bool isLoop = false; foreach (JToken childToken in tokens) { if (childToken.Type == JTokenType.Array && (parentToken as JProperty).Name.Trim() != "#") { JArray arrayToken = childToken as JArray; List <object> itemsToAdd = new List <object>(); foreach (JToken arrEl in childToken.Children()) { object itemToAdd = arrEl.Value <JToken>(); if (arrEl.Type == JTokenType.String && arrEl.ToString().Trim().StartsWith("#")) { object value = ParseFunction(arrEl.ToString(), inputJson, parentArray, currentArrayToken, localContext); itemToAdd = value; } itemsToAdd.Add(itemToAdd); } arrayToken.RemoveAll(); foreach (object itemToAdd in itemsToAdd) { arrayToken.Add(itemToAdd); } } if (childToken.Type == JTokenType.Property) { JProperty property = childToken as JProperty; if (property.Name != null && property.Name == "#" && property.Value.Type == JTokenType.Array) { JArray values = property.Value as JArray; JEnumerable <JToken> arrayValues = values.Children(); foreach (JToken arrayValue in arrayValues) { if (arrayValue.Type == JTokenType.String && ExpressionHelper.TryParseFunctionNameAndArguments( arrayValue.Value <string>().Trim(), out string functionName, out string arguments)) { if (functionName == "copy") { if (selectedTokens == null) { selectedTokens = new List <JToken>(); } selectedTokens.Add(Copy(arguments, inputJson, localContext)); } else if (functionName == "replace") { if (tokensToReplace == null) { tokensToReplace = new Dictionary <string, JToken>(); } var replaceResult = Replace(arguments, inputJson, localContext); tokensToReplace.Add(replaceResult.Key, replaceResult.Value); } else if (functionName == "delete") { if (tokensToDelete == null) { tokensToDelete = new List <JToken>(); } tokensToDelete.Add(Delete(arguments, inputJson, localContext)); } } } } if (property.Name != null && property.Value.ToString().Trim().StartsWith("#") && !property.Name.Contains("#eval") && !property.Name.Contains("#ifgroup") && !property.Name.Contains("#loop")) { object newValue = ParseFunction(property.Value.ToString(), inputJson, parentArray, currentArrayToken, localContext); property.Value = GetToken(newValue, localContext); } /* For looping*/ isLoop = false; if (property.Name != null && property.Name.Contains("#eval")) { ExpressionHelper.TryParseFunctionNameAndArguments(property.Name, out string functionName, out string functionString); object functionResult = ParseFunction(functionString, inputJson, null, null, localContext); JProperty clonedProperty = new JProperty(functionResult.ToString(), property.Value); if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); if (tokensToAdd == null) { tokensToAdd = new List <JToken> { clonedProperty }; } } if (property.Name != null && property.Name.Contains("#ifgroup")) { ExpressionHelper.TryParseFunctionNameAndArguments(property.Name, out string functionName, out string functionString); object functionResult = ParseFunction(functionString, inputJson, null, null, localContext); bool result = false; try { result = (bool)ReflectionHelper.GetTypedValue(typeof(bool), functionResult, GetEvaluationMode(localContext)); } catch { if (IsStrictMode(localContext)) { throw; } result = false; } if (result == true) { if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); RecursiveEvaluate(childToken, inputJson, parentArray, currentArrayToken, localContext); if (tokenToForm == null) { tokenToForm = new List <JToken>(); } foreach (JToken grandChildToken in childToken.Children()) { tokenToForm.Add(grandChildToken.DeepClone()); } } else { if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); } isLoop = true; } if (property.Name != null && property.Name.Contains("#loop")) { string strArrayToken = property.Name.Substring(6, property.Name.Length - 7); var jsonToLoad = inputJson; if (currentArrayToken != null && property.Name.Contains("#loopwithincontext")) { strArrayToken = property.Name.Substring(19, property.Name.Length - 20); jsonToLoad = JsonConvert.SerializeObject(currentArrayToken); } JToken token = JsonConvert.DeserializeObject <JObject>(jsonToLoad); JToken arrayToken = null; if (strArrayToken.Contains("#")) { int sIndex = strArrayToken.IndexOf("#"); string sub1 = strArrayToken.Substring(0, sIndex); int indexOfENdFubction = GetIndexOfFunctionEnd(strArrayToken); if (indexOfENdFubction > sIndex && sIndex > 0) { string sub2 = strArrayToken.Substring(indexOfENdFubction + 1, strArrayToken.Length - indexOfENdFubction - 1); string functionResult = ParseFunction(strArrayToken.Substring(sIndex, indexOfENdFubction - sIndex + 1), inputJson, parentArray, currentArrayToken, localContext).ToString(); strArrayToken = sub1 + functionResult + sub2; } } try { arrayToken = token.SelectToken(strArrayToken); if (arrayToken is JObject) { arrayToken = new JArray(arrayToken); } } catch { var multipleTokens = token.SelectTokens(strArrayToken); arrayToken = new JArray(multipleTokens); } if (arrayToken == null) { arrayToForm = new JArray(); } else { JArray array = (JArray)arrayToken; IEnumerator <JToken> elements = array.GetEnumerator(); while (elements.MoveNext()) { if (arrayToForm == null) { arrayToForm = new JArray(); } JToken clonedToken = childToken.DeepClone(); RecursiveEvaluate(clonedToken, inputJson, array, elements.Current, localContext); foreach (JToken replacedProperty in clonedToken.Children()) { arrayToForm.Add(replacedProperty); } } } if (loopProperties == null) { loopProperties = new List <string>(); } loopProperties.Add(property.Name); isLoop = true; } /*End looping */ } if (childToken.Type == JTokenType.String && childToken.Value <string>().Trim().StartsWith("#") && parentArray != null && currentArrayToken != null) { object newValue = ParseFunction(childToken.Value <string>(), inputJson, parentArray, currentArrayToken, localContext); JToken replaceToken = GetToken(newValue, localContext); childToken.Replace(replaceToken); } if (!isLoop) { RecursiveEvaluate(childToken, inputJson, parentArray, currentArrayToken, localContext); } } if (selectedTokens != null) { foreach (JToken selectedToken in selectedTokens) { if (selectedToken != null) { JEnumerable <JToken> copyChildren = selectedToken.Children(); foreach (JToken copyChild in copyChildren) { JProperty property = copyChild as JProperty; (parentToken as JObject).Add(property.Name, property.Value); } } } } if (tokensToReplace != null) { foreach (KeyValuePair <string, JToken> tokenToReplace in tokensToReplace) { JToken selectedToken = (parentToken as JObject).SelectToken(tokenToReplace.Key); if (selectedToken != null && selectedToken is JObject) { JObject selectedObject = selectedToken as JObject; selectedObject.RemoveAll(); JEnumerable <JToken> copyChildren = tokenToReplace.Value.Children(); foreach (JToken copyChild in copyChildren) { JProperty property = copyChild as JProperty; selectedObject.Add(property.Name, property.Value); } } if (selectedToken != null && selectedToken is JValue) { JValue selectedObject = selectedToken as JValue; selectedObject.Value = tokenToReplace.Value.ToString(); } } } if (tokensToDelete != null) { foreach (string selectedToken in tokensToDelete) { JToken tokenToRemove = parentToken.SelectToken(selectedToken); if (tokenToRemove != null) { tokenToRemove.Ancestors().First().Remove(); } } } if (tokensToAdd != null) { foreach (JToken token in tokensToAdd) { (parentToken as JObject).Add((token as JProperty).Name, (token as JProperty).Value); } } if (tokenToForm != null) { foreach (JToken token in tokenToForm) { foreach (JProperty childToken in token.Children()) { (parentToken as JObject).Add(childToken.Name, childToken.Value); } } } if (parentToken is JObject) { (parentToken as JObject).Remove("#"); } if (loopProperties != null) { foreach (string propertyToDelete in loopProperties) { (parentToken as JObject).Remove(propertyToDelete); } } if (arrayToForm != null) { parentToken.Replace(arrayToForm); } }