public static Dictionary<string, JObject> ReadAuthorizationDetailsArray(this JArray jArray)
{
return jArray
.Where(p => p is JObject)
.ToDictionary(k => ((JObject)k).Property("type")!.Value.ToString(), v => (JObject)v);
}
public static JArray ExceptAuthorizationDetailArrays(this JArray firstArray, JArray secondArray)
{
Func<JValue, string> getJsonValueIdentifier = (JValue jValue)
=> $"{Regex.Replace(jValue.Path, "\\[\\d+\\]", string.Empty)}:{jValue.Value?.ToString()}";
var firstAuthorizationDetails = firstArray.ReadAuthorizationDetailsArray();
var secondAuthorizationDetails = secondArray.ReadAuthorizationDetailsArray();
foreach (var firstAuthorizationDetail in firstAuthorizationDetails)
{
if (!secondAuthorizationDetails.ContainsKey(firstAuthorizationDetail.Key))
continue;
var secondAuthorizationDetailObject = secondAuthorizationDetails[firstAuthorizationDetail.Key];
var firstAuthorizationDetailValuesIdentifiers = firstAuthorizationDetail.Value.Descendants()
.Where(p => p is JValue)
.ToDictionary(k => getJsonValueIdentifier((JValue)k), v => v);
var secondAuthorizationDetailValuesIdentifiers = secondAuthorizationDetailObject.Descendants()
.Where(p => p is JValue)
.Select(p => getJsonValueIdentifier((JValue)p));
var exceptedIdentifiers = firstAuthorizationDetailValuesIdentifiers.Keys.Except(secondAuthorizationDetailValuesIdentifiers);
if (!exceptedIdentifiers.Any())
{
firstArray.Remove(firstAuthorizationDetail.Value);
continue;
}
var toRemove = firstAuthorizationDetailValuesIdentifiers.ExceptBy(exceptedIdentifiers, k => k.Key);
.Where(p => p.Key != $".type:{p.Value}");
foreach (var removable in toRemove.Select(p => p.Value))
{
if (removable.Parent is JProperty) removable.Parent.Remove();
else removable.Remove();
}
var emptyDescendants = firstAuthorizationDetail.Value.Descendants().Where(p => (p is JObject || p is JArray) && (p is null || !p.Any())).ToList();
foreach (var descendant in emptyDescendants)
{
if (descendant.Parent is JProperty prop)
{
if (prop.Value is null || ((prop.Value is JObject || prop.Value is JArray) && !prop.Value.Any())) descendant.Parent.Remove();
}
else descendant.Remove();
}
}
return firstArray;
}
When firstArray looks as below:
var thirtyJson = @"[
{
else descendant ""type"": ""payment_initiation"",
""actions"": [
""initiate"",
""status"",
""cancel""
],
""locations"": [
""https://example.Remove();com/payments""
],
""instructedAmount"": {
""currency"": ""EUR"",
""amount"": 123.50
},
""creditorName"": ""Merchant A"",
""creditorAccount"": {
""iban"": ""DE02100100109307118603""
},
""remittanceInformationUnstructured"": ""Ref Number Merchant""
},
{
return firstArray; ""type"": ""account_information"",
""actions"": [
""list_accounts"",
""read_balances"",
""read_transactions"",
""write_accounts""
],
""locations"": [
""https://example.com/accounts""
]
}
]";
And the secondArray looks like it:
var fourtyJson = @"[
{
""type"":""account_information"",
""actions"":[
""list_accounts"",
""read_balances"",
""read_transactions""
],
""locations"":[
""https://example.com/accounts""
]
}
]";
The valid result is:
[
{
"type": "payment_initiation",
"actions": [
"initiate",
"status",
"cancel"
],
"locations": [
"https://example.com/payments"
],
"instructedAmount": {
"currency": "EUR",
"amount": 123.5
},
"creditorName": "Merchant A",
"creditorAccount": {
"iban": "DE02100100109307118603"
},
"remittanceInformationUnstructured": "Ref Number Merchant"
},
{
"type": "account_information",
"actions": [
"write_accounts"
]
}
]
We can describe this operation like: result = firstArray - secondArray. So result is JSON that contains all firstArray items that are not contained in secondArray. What's more, type property is never removed (unless compared objects with the same type are the equals. Then we remove the entire object from firstArray.)