using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
private static readonly object lockObject = new object();
public static void Main()
{ 'title': 'Book 1', 'price': 10 },
{ 'title': 'Book 2', 'price': 15.4 }
""colorx"": ""read->$.store.book[?(@.title == 'Book 2')]|object|transform(title=>a:Name2,a:Value;price=>a:Name2,a:Value)"",
""pricex"": ""read->$.store['a:bicycle']|object|transform(color=>a:Name,a:Value;price=>a:Name,a:Value)"",
""modelx"": ""read->$.store.book[?(@.title == 'Book 2')].price|number""
Console.WriteLine(TransformJsonToJson(jsonInput, json));
public static string TransformJsonToJson(string jsonInput, string jsonOutput)
JObject inputObject = JObject.Parse(jsonInput);
string pattern = @"(?:read|build)->[^""]*(?:'[^']*')*[^""]*";
MatchCollection matches = Regex.Matches(jsonOutput, pattern);
foreach (Match match in matches)
string fetchValue = match.Value;
var parts = fetchValue.Split(new[] { "->" }, StringSplitOptions.RemoveEmptyEntries);
var pipeline = parts[1].Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
string jsonPath = pipeline[0];
string type = pipeline.Length > 1 ? pipeline[1] : "string";
string transformFunc = pipeline.Length > 2 ? pipeline[2] : "";
var selectedToken = type == "object" ? inputObject.SelectToken(jsonPath) :
(type == "array" ? inputObject.SelectTokens(jsonPath) :
(type == "string" ? inputObject.SelectToken(jsonPath) : inputObject.SelectToken(jsonPath)));
if (selectedToken != null)
jsonOutput = jsonOutput.Replace(fetchValue, selectedToken.ToString());
jsonOutput = jsonOutput.Replace(fetchValue, selectedToken.ToString());
jsonOutput = jsonOutput.Replace(String.Format("\"{0}\"",fetchValue), selectedToken.ToString());
string patternInner = @"transform\(([^)]+)\)";
Match matchInner = Regex.Match(transformFunc, patternInner);
string capturedContent = matchInner.Groups[1].Value;
JObject transformedObject = TransformJson(selectedToken as JObject, "result==" + capturedContent);
jsonOutput = jsonOutput.Replace(String.Format("\"{0}\"",fetchValue), transformedObject["result"].ToString());
jsonOutput = jsonOutput.Replace(String.Format("\"{0}\"",fetchValue), selectedToken.ToString());
jsonOutput = jsonOutput.Replace(fetchValue, selectedToken.ToString());
public static JObject TransformJson(JObject originalObject, string mappingPattern)
var configs = mappingPattern.Split(new[] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
JObject transformedObject = new JObject();
foreach (var config in configs)
var parts = config.Split(new[] { "==" }, StringSplitOptions.RemoveEmptyEntries);
var resultKeyName = parts[0];
var mappingPatternSub = parts[1];
var mappings = ParseMappingPattern(mappingPatternSub);
JArray resultArray = new JArray();
foreach (var mapping in mappings)
var subMappings = mapping.Value;
var regex = new Regex(@"(?<arrayName>\w+)\[(?<conditions>[^]]+)\]\.(?<property>\w+)");
var match = regex.Match(key);
string arrayName = match.Groups["arrayName"].Value;
string conditions = match.Groups["conditions"].Value;
string propertyName = match.Groups["property"].Value;
var conditionParts = conditions.Split(new[] { "&&" }, StringSplitOptions.RemoveEmptyEntries)
JArray array = (JArray)originalObject[arrayName];
foreach (var item in array)
JObject job = (JObject)item;
bool allConditionsMatch = true;
foreach (var condition in conditionParts)
var conditionMatch = Regex.Match(condition, @"(?<attribute>\w+)='(?<value>[^']+)'");
if (conditionMatch.Success)
string attributeName = conditionMatch.Groups["attribute"].Value;
string attributeValue = conditionMatch.Groups["value"].Value;
if (job[attributeName] == null || job[attributeName].ToString() != attributeValue)
allConditionsMatch = false;
string result = element[propertyName].ToString();
var jobObj = new JObject();
foreach (var subMapping in subMappings)
if (subMapping.Key == "key")
var part = subMapping.Value.Split(new[] { ">" }, StringSplitOptions.RemoveEmptyEntries);
jobObj[part[0]] = part.Length > 1 ? part[1] : part[0];
if (subMapping.Key == "value")
var part = subMapping.Value.Split(new[] { ">" }, StringSplitOptions.RemoveEmptyEntries);
jobObj[part[0]] = element[propertyName];
Console.WriteLine("No match found for conditions [{conditions}] in {arrayName}.");
var tokens = key.Split('.');
JToken currentToken = originalObject;
foreach (var token in tokens)
currentToken = currentToken[token];
if (currentToken == null)
if (currentToken != null && subMappings.ContainsKey("key") && subMappings.ContainsKey("value"))
var partsName = subMappings["key"].Split(new[] { ">" }, StringSplitOptions.RemoveEmptyEntries);
var fieldName = partsName[0];
var renameValue = partsName.Length > 1 ? partsName[1] : tokens.Last();
resultArray.Add(new JObject
{ fieldName, renameValue },
{ subMappings["value"], currentToken.ToString() }
transformedObject[resultKeyName] = resultArray;
return transformedObject;
static Dictionary<string, Dictionary<string, string>> ParseMappingPattern(string mappingPattern)
var mappings = new Dictionary<string, Dictionary<string, string>>();
var pairs = mappingPattern.Split(';');
foreach (var pair in pairs)
var splitPair = pair.Split(new[] { "=>" }, StringSplitOptions.RemoveEmptyEntries);
var subMapping = splitPair[1].Split(',');
var subMappingDict = new Dictionary<string, string>();
subMappingDict["key"] = subMapping[0];
subMappingDict["value"] = subMapping[1];
mappings[key] = subMappingDict;