The use case is pretty simple in concept. I receive a json payload that has two properties on the root level:
instructions
base
Instructions are set of instructions that I am supposed to apply on the base json object.
For eg - according to the below payload,
- I am supposed to traverse to the widgets within
defaultWidgets
of the base property. - Then replace it completely with whatever is the value of
patchedValue
.
Input Payload:
{
"instructions": [
{
"patchedPath": "defaultWidget.widgets",
"patchedValue": false,
}
],
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": [
{
"managerId": "defaultWidget",
"widgetId": "invCreateWid7",
"type": "standard",
"manifestPath": "[email protected]",
"defaultInputManifestPath": "[email protected]",
"title": "scannedInvoice",
"children": [
{
"name": "tom"
}
],
"hash": "ktocle2lrgps9",
"directives": ""
}
]
}
}
}
The result should be :
{
"base": {
"defaultWidget": {
"hash": "ktocle2l0u527",
"layout": "6|6",
"managerId": "defaultWidget",
"widgets": false
}
}
}
Code:
var stringPayload = "{ \"instructions\": [ { \"patchedPath\": \"defaultWidget.widgets\", \"patchedValue\": false, } ], \"base\": { \"defaultWidget\": { \"hash\": \"ktocle2l0u527\", \"layout\": \"6|6\", \"managerId\": \"defaultWidget\", \"widgets\": [ { \"managerId\": \"defaultWidget\", \"widgetId\": \"invCreateWid7\", \"type\": \"standard\", \"manifestPath\": \"[email protected]\", \"defaultInputManifestPath\": \"[email protected]\", \"title\": \"scannedInvoice\", \"children\": [ { \"name\": \"tom\" } ], \"hash\": \"ktocle2lrgps9\", \"directives\": \"\" } ] } }}";
var parsedPayload = JsonConvert.DeserializeObject(stringPayload);
var baseJ = parsedPayload.GetType().GetProperty("instructions").GetValue(parsedPayload, null);
string jsonString = JsonConvert.SerializeObject(parsedPayload);
I am stuck on the very initial steps , I am getting:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Type.GetProperty(...) returned null.
This is what QuickWatch says:
CodePudding user response:
What's returned by DeserializeObject
in this case is JObject
so to start with you can cast to it:
var parsedPayload = (JObject) JsonConvert.DeserializeObject(stringPayload);
Then grab instructions and target to change:
var instructions = (JArray) parsedPayload["instructions"]; // cast to JArray
var result = parsedPayload["base"];
Then we can go over instructions and apply them:
foreach (var instruction in instructions) {
// grab target path and value
var targetPath = (string) ((JValue)instruction["patchedPath"]).Value;
var targetValue = (JValue)instruction["patchedValue"];
// temp variable to traverse the path
var target = result;
foreach (var part in targetPath.Split('.')) {
target = target[part];
}
// replace the value
target.Replace(targetValue);
}
Now result contains what was in base with instructions applied.
CodePudding user response:
With Json.NET you can do that like this:
var json = File.ReadAllText("sample.json");
var semiParsedJson = JObject.Parse(json);
var instructions = (JArray)semiParsedJson["instructions"];
var @base = semiParsedJson["base"];
foreach (var instruction in instructions)
{
var path = (string)instruction["patchedPath"];
var newValue = (string)instruction["patchedValue"];
var toBeReplaced = @base.SelectToken(path);
toBeReplaced.Replace(newValue);
}
JObject.Parse
parses the json string- With the index operator
[]
we retrieve the two top level nodes. - One of them is an array (that's why there is an explicitJArray
cast) - The other one is a
JToken
- We iterate through the array and retrieve the
path
and thenewvalue
- We use the
SelectToken
to get the desired node and then apply the replacement via theReplace
method.
Please bear in mind that this solution is not bulletproof. You might need to change the indexer operator to TryGetValue
to be able to check existence before you perform any operation on the JToken
.
You also need to check that the patchedPath
is valid at all.