问题
Note: Im working with System.Text.Json package
Below is JSON I am getting from a database. I have to go through each of the keys in the JSON and check if there is a period (.
) in the key name; if so, I need to add a property required
with the value of true
in the JSON in order to provide runtime validation:
validate:{"required", true}
Here is my JSON:
{
"display": "wizard",
"settings": {},
"components": [{
"title": "Event Information",
"label": "Event Information",
"type": "panel",
"key": "EventInformation",
"components": [{
"label": "Row1Columns",
"columns": [{
"components": [{
"label": "Event Date",
"format": "dd/MM/yyyy hh:mm a",
"tableView": false,
"datePicker": {
"disableWeekends": false,
"disableWeekdays": false
},
"validate": {
"unique": true
},
"key": "Event.EventDate",
"type": "datetime",
"input": true,
"suffix": "<i ref=\"icon\" class=\"fa fa-calendar\" style=\"\"></i>",
"widget": {
"type": "calendar",
"displayInTimezone": "viewer",
"language": "en",
"useLocaleSettings": false,
"allowInput": true,
"mode": "single",
"enableTime": true,
"noCalendar": false,
"format": "dd/MM/yyyy hh:mm a",
"hourIncrement": 1,
"minuteIncrement": 1,
"time_24hr": false,
"minDate": null,
"disableWeekends": false,
"disableWeekdays": false,
"maxDate": null
}
}],
"width": 6,
"offset": 0,
"push": 0,
"pull": 0
}, {
"components": [{
"label": "Duration (minutes)",
"mask": false,
"spellcheck": true,
"tableView": false,
"delimiter": false,
"requireDecimal": false,
"inputFormat": "plain",
"key": "Event.Duration",
"type": "number",
"input": true
}],
"width": 6,
"offset": 0,
"push": 0,
"pull": 0
}],
"tableView": false,
"key": "row1Columns",
"type": "columns",
"input": false
}, {
"label": "Row2Columns",
"columns": [{
"components": [{
"label": "Event Category",
"widget": "choicesjs",
"tableView": true,
"dataSrc": "custom",
"data": {
"custom": "values = getEventCategoryValues()"
},
"valueProperty": "AgencyEventCategoryId",
"template": "<span>{{ item.text }}</span>",
"selectThreshold": 0.3,
"validate": {
"required": true
},
"key": "Event.AgencyEventCategoryId",
"type": "select",
"indexeddb": {
"filter": {}
},
"input": true
}],
"width": 6,
"offset": 0,
"push": 0,
"pull": 0
}, {
"components": [{
"label": "Attendance",
"widget": "choicesjs",
"tableView": true,
"multiple": false,
"dataSrc": "custom",
"data": {
"custom": "values = getAttendanceValues()"
},
"valueProperty": "AgencyEventAttendanceId",
"template": "<span>{{ item.text }}</span>",
"selectThreshold": 0.3,
"validate": {
"required": true,
},
"key": "Event.AgencyEventAttendanceId",
"type": "select",
"indexeddb": {
"filter": {}
},
"input": true
}],
"width": 6,
"offset": 0,
"push": 0,
"pull": 0
}],
"tableView": false,
"key": "row2Columns",
"type": "columns",
"input": false
}, {
"label": "Event Options",
"widget": "choicesjs",
"tableView": true,
"multiple": true,
"dataSrc": "custom",
"data": {
"custom": "values = getEventManagerValues(data.Event.AgencyEventCategoryId)"
},
"template": "<span>{{ item.text }}</span>",
"refreshOn": "Event.AgencyEventCategoryId",
"clearOnRefresh": true,
"selectThreshold": 0.3,
"calculateServer": false,
"validate": {
"required": true,
"multiple": true
},
"key": "Event.EventDetail",
"type": "select",
"indexeddb": {
"filter": {}
},
"input": true
}, {
"label": "Casenote",
"wysiwyg": true,
"autoExpand": true,
"spellcheck": true,
"tableView": true,
"calculateServer": false,
"key": "Event.EventCasenote[0].Casenote",
"type": "textarea",
"input": true
}],
"input": false,
"tableView": false,
"breadcrumbClickable": true,
"buttonSettings": {
"previous": true,
"cancel": true,
"next": true
},
"collapsible": false
}]
}
回答1:
I was having similar issue, and have found a solution, see below the code and comments. I am using Newtonsoft
though but it is worth checking if you can use Newtonsoft
library and have not found a solution for System.Text.Json
.
All controls in your JSON
are part of component object/array so we can use JSONPath
, see the link for more details.
public void IterateJson(JObject obj, string mandatoryFieldKey)
{
JToken jTokenFoundForMandatoryField = obj.SelectToken
("$..components[?(@.key == '" + mandatoryFieldKey + "')]");
//Now we convert this oken into an object so that we can add properties/objects in it
if (jTokenFoundForMandatoryField is JObject jObjectForMandatoryField)
{
//We check if validate already exists for this field, if it does not
//exists then we add validate and required property inside the if condition
if (jObjectForMandatoryField["validate"] == null)
jObjectForMandatoryField.Add("validate",
JObject.FromObject(new { required = true })); //add validate and required property
else
{
//If validate does not exists then code comes here and
//we convert the validate into a JObject using is JObject statement
if (jObjectForMandatoryField["validate"] is JObject validateObject)
{
//We need to check if required property already exists,
//if it does not exists then we add it inside the if condition.
if (validateObject["required"] == null)
{
validateObject.Add("required", true); //add required property
}
}
}
}
}
回答2:
One of the options would be to parse json into JObject and add property to it via Newtonsoft's Json.NET:
var obj = JObject.Parse("{'key':'value'}");
obj.Add("required", true);
Console.WriteLine(obj); // { "key": "value", "required": true }
To add new object you can use this overload of Add
:
obj.Add("validate", JObject.FromObject(new { required = true }));
So the whole solution will look something like this:
var obj = JObect.Parse(your_json);
foreach(var token in obj.DescendantsAndSelf().ToList()) // ToList is important!!!
{
if(token is JObject xObj)
{
// check your conditions for adding property
// check if object does not have "validate" property
if(satisfies_all_conditions)
{
xObj.Add("validate", JObject.FromObject(new { required = true }));
}
}
}
回答3:
It was interesting task for me, so this is what i have written
class Program
{
static void Main(string[] args)
{
string jsonFilePath = @"test.json"; //path to your json
string json = File.ReadAllText(jsonFilePath);
var data = JObject.Parse(json);
CheckJson(data);
Console.ReadLine();
}
static void CheckJson(JToken value)
{
if (value.Values().Count() != 0) //if more than 0 - so value is object or array and we have to call this method for each property
{
foreach (var item in value.Values().ToList())
{
CheckJson(item);
}
}
else if (true) //else - we have exactly value of key, which we can check, for example if . exists or additional checks
{
if (value.Parent.Parent is JObject jObject && jObject["validate"] == null) //check if above "required" property exists
{
jObject.Add("validate", JObject.FromObject(new { required = true })); //add required property
}
}
}
}
This code will add in each object property "required" if it is not exists. All you need - just add Validation method and call it in if block. And better to add additional validation that won't continue checking all properties if "required" property exists
来源:https://stackoverflow.com/questions/62087264/how-to-add-properties-at-runtime-to-json-c