Modification of the json value in c#. model a correct parsing way
I have written my code where I read an api and get the json output as below.
{"BaseObject":"P|GL",
"bbl:BL|12|11":"BL|GL|01",
"kind": "Entity",
"BaseObjectDescription":"PlayerBatsman",
"bbl:B827222":"downBatsman",
"CreateDate":"06.01.2022",
"Description":"PlayerBatsman",
"errors": [
{
"ErrorMessage": "MissingUnit",
"ObjType": "Property",
"Object": "test:batsman",
"RefObject": "bbl:BATS364"} ],
"bbl:NO87872":"GHG66762",
"bbl:PONI9912":"bbl:NOI65661",
"bbl:KOK1022":"KOK002",
"bbl:997171SD":"bbl:YUT12232",
"bbl:89812":false,
"bbl:4894":"pd:96",
"bbl:KITE212":"pd:QUTEQ001",
"ProjectCategory":"Feed",
"bbf:type":["[\"bbl:P3924\",
\"boss:Noball\"]"],
"primarybbf:type":"[\"bbl:P101003924\",\"boss:Tag\"]"}
But now I need to modify my output as something like this :
{
data": {
"kind": "ENTITY",
"payload": {
"tag-batsman:attributes": {
"bbl:B827222":"downBatsman",
"bbl:BATS364": null,
"bbl:NO87872":"GHG66762",
"bbl:KOK1022":"KOK002",
"bbl:89812":false
},
"relations": {
"bbl:PONI9912":[
"NOI65661"
],
"bbl:997171SD": [
"YUT12232"
],
"bbl:4894": [
"pd:96"
],
"bbl:KITE212": [
"pd:QUTEQ001"
],
"tag-bbf-pubsub:type": [
"P3924",
"P101003823",
"P101003856",
"P101003858",
"P101003932",
"P101004021"
]
},
},
},
"type": "EQUIPMENT",
"version": "data-4-build-606"
}
}
Basically what I need is to create this json where if "bbl:xyz" key in input json contains bbl: or pd: in their values then they go under "relations" key of output json as shown above and rest all bbl:xyz will go under "attributes" key as shown in above Json model, rest keys and values pair are constant and can be managed. How can I do it in C#?
For starting lets say my input json is recorded as a stream in response message below. How do I proceed from here?
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var req1 = await ProxyRequest(req.Body);
var responseMessage = await req1.Content.ReadAsStreamAsync();
Solution 1:
I'm not sure I fully understood all the requirements and the mapping is not completely clear to me, but you could utilize a library like Newtonsoft.Json
to do something like this. I assume this sample should get you on the right track at least.
internal class JsonTranslatorOptions
{
public JsonTranslatorOptions(
string kind,
string type,
string version)
{
Kind = kind;
Type = type;
Version = version;
}
public string Kind { get; }
public string Type { get; }
public string Version { get; }
}
internal enum PropertySection
{
None,
Attribute,
Relation
}
internal class JsonTranslator
{
private const string KeyKeyword = "bbl:";
private static readonly string[] ValueKeywords = { KeyKeyword, "pd:" };
private readonly JObject _attributes = new();
private readonly JObject _data = new();
private readonly JObject _payload = new();
private readonly JObject _relations = new();
private readonly JObject _root = new();
public JsonTranslator(JsonTranslatorOptions options)
{
Initialize(options);
}
public JObject Translate(JObject input)
{
TraverseObject(input);
return _root;
}
private void TraverseObject(JObject input)
{
foreach (JProperty property in input.Properties())
{
TraverseProperty(property);
}
}
private void TraverseArray(JArray array)
{
foreach (JToken element in array)
{
if (element is JValue)
{
continue;
}
foreach (JProperty property in ((JObject)element).Properties())
{
TraverseProperty(property);
}
}
}
private void TraverseProperty(JProperty property)
{
switch (property.Value.Type)
{
case JTokenType.Object:
TraverseObject((JObject)property.Value);
break;
case JTokenType.Array:
TraverseArray((JArray)property.Value);
break;
default:
MapPropertyValue(property);
break;
}
}
private void MapPropertyValue(JProperty property)
{
switch (GetPropertySection(property))
{
case PropertySection.Attribute:
_attributes.Add(property);
break;
case PropertySection.Relation:
_relations.Add(property);
break;
}
}
private static PropertySection GetPropertySection(JProperty property)
{
var value = property.Value.Value<string?>();
if (!property.Name.Contains(KeyKeyword))
{
return PropertySection.None;
}
if (value is null || !ValueKeywords.Any(keyword => value.Contains(keyword)))
{
return PropertySection.Attribute;
}
return PropertySection.Relation;
}
private void Initialize(JsonTranslatorOptions options)
{
_root.Add("data", _data);
InitializeData(options);
}
private void InitializeData(JsonTranslatorOptions options)
{
_data.Add("kind", options.Kind);
_data.Add("payload", _payload);
_data.Add("type", options.Type);
_data.Add("version", options.Version);
InitializePayload();
}
private void InitializePayload()
{
_payload.Add("tag-batsman:attributes", _attributes);
_payload.Add("relations", _relations);
}
}
Using it should look like this:
var json = JObject.Parse(@"{""BaseObject"":""P | GL"",""bbl: BL | 12 | 11"":""BL | GL | 01"",""BaseObjectDescription"":""PlayerBatsman"",""bbl: B827222"":""downBatsman"",""CreateDate"":""06.01.2022"",""Description"":""PlayerBatsman"",""errors"":[{""ErrorMessage"":""MissingUnit"",""ObjType"":""Property"",""Object"":""test: batsman"",""RefObject"":""bbl: BATS364""}],""bbl: NO87872"":""GHG66762"",""bbl: PONI9912"":""bbl: NOI65661"",""bbl: KOK1022"":""KOK002"",""bbl: 997171SD"":""bbl: YUT12232"",""bbl: 89812"":false,""bbl: 4894"":""pd: 96"",""bbl: KITE212"":""pd: QUTEQ001"",""ProjectCategory"":""Feed"",""bbf: type"":[""[\""bbl:P3924\"",\""boss:Noball\""]""], ""primarybbf:type"":""[\""bbl:P101003924\"",\""boss:Tag\""]""}");
var options = new JsonTranslatorOptions(
kind: "ENTITY",
type: "EQUIPMENT",
version: "data-4-build-606");
var translator = new JsonTranslator(options);
var output = translator.Translate(json);
Console.WriteLine(output.ToString());
The current output it's giving:
{
"data": {
"kind": "ENTITY",
"payload": {
"tag-batsman:attributes": {
"bbl: 89812": false
},
"relations": {
"bbl: PONI9912": "bbl: NOI65661",
"bbl: 997171SD": "bbl: YUT12232",
"bbl: 4894": "pd: 96",
"bbl: KITE212": "pd: QUTEQ001"
}
},
"type": "EQUIPMENT",
"version": "data-4-build-606"
}
}