I have a very large json schema which I would like to display in an Angular Tree Control. However, the json schema is not exactly in the treemodel format supported by the Angular Tree Control. For example, the children (properties) in the schema are not in an array. How would I go about converting the json schema into a treemodel format?
The schema looks something like this (except more complicated with up to 10 levels of nesting):
{
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"address": {
"type": "object",
"properties": {
"addressLine1": {
"type": "string"
},
"addressLine2": {
"type": "string"
}
}
}
}
}
For it to render correctly in the Angular Tree Control, it needs to look like this:
{
"type": "object",
"properties": [
{
"name": "firstName",
"type": "string"
},
{
"name": "lastName",
"type": "string"
},
{
"name": "address",
"type": "object",
"properties": [
{
"name": "addressLine1",
"type": "string"
},
{
"name": "addressLine2",
"type": "string"
}
]
}
]
}
This is an example, can be refactored to be recursive to deeper levels.
var data = {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"address": {
"type": "object",
"properties": {
"addressLine1": {
"type": "string"
},
"addressLine2": {
"type": "string"
}
}
}
}
};
function toTreeModel(obj){
var treeModel = {};
for (var a in obj) {
if(a === 'properties'){
treeModel[a] = []
var i = 0;
var e = 0;
for(b in obj[a]){
if(obj[a][b].type === 'object'){
treeModel[a][i] = {name: b, type: obj[a][b].type, properties: []};
for(c in obj[a][b].properties){
treeModel[a][i].properties.push({name: c, type: obj[a][b].properties[c].type});
e++;
}
} else {
treeModel[a][i] = {name: b, type: obj[a][b].type};
}
i++;
}
} else {
treeModel[a] = obj[a];
}
}
return treeModel;
}
var toTree = toTreeModel(data);
// console.log(toTree);
document.getElementById("output").innerHTML = JSON.stringify(toTree, undefined, 2);
<pre id="output">
</pre>
it support nested also
var data = {
"type": "object",
"properties": {
"checked": {
"type": "boolean",
},
"dimensions": {
"type": "object",
"properties": {
"width": {
"type": "integer",
},
"height": {
"type": "integer",
},
"volume": {
"type": "object",
"properties": {
"length": {
"type":"integer",
},
"breadth":{
"type": "integer"
}
}
}
}
},
"id": {
"type": "integer",
},
"name": {
"type": "string",
},
"price": {
"type": "number",
}
}
}
function findProperties(obj){
let properties = []
for(key in obj){
if(obj[key].properties){
properties.push({name: key, datatype: obj[key].type, properties: findProperties(obj[key].properties)})
}else{
properties.push({ name: key, datatype: obj[key].type});
}
}
return properties;
}
function findData(data){
let result = "";
for(key in data){
if(key == 'properties'){
result = findProperties(data.properties)
}
}
return result;
}
console.log(JSON.stringify(findData(data)));
Related
I have a function to generate an object which I'm transforming to a JSON later on:
function createSearchCriteria(payload) {
var output = [];
if (payload['searchCriteria'] != null) {
for (var i = 0; i < payload['searchCriteria'].length; i++) {
var content = payload['searchCriteria'][i];
output[i] = {};
if (content['grouping'] != null) {
output[i]['groupOperator'] = content['grouping'];
output[i]['searchCriteria'] = [];
output[i]['searchCriteria'].push(createSearchCriteria(content))
} else {
output[i]['name'] = content['name'];
output[i]['type'] = content['type'];
}
}
}
return output
}
The input payload for this method is also a JSON value parsed
payload = JSON.parse(request);
The input structure is almost the same as the output, the only difference is the "grouping" attribute, which in the output is called "groupOperator".
I have implemented my function recursive because we can have different levels of search criteria.
Even though the searchCriteria in the input has only one [] each.
Why does each searchCriteria in the result comes with 2 pairs of squared brackets?
{
"searchCriteria": [
{
"groupOperator": "AND",
"searchCriteria": [
[
{
"groupOperator": "OR",
"searchCriteria": [
[
{
"name": "FirstName",
"type": "string"
},
{
"name": "LastName",
"type": "string"
},
{
"name": "MiddleName",
"type": "string"
},
{
"name": "Document",
"type": "string"
},
{
"name": "DOB",
"type": "date"
},
{
"name": "CdrId",
"type": "string"
}
]
]
},
{
"groupOperator": "AND",
"searchCriteria": [
[
{
"name": "Active",
"type": "bool"
},
{
"name": "Id",
"type": "int"
},
{
"name": "CountryId",
"type": "int"
}
]
]
}
]
]
}
],
"groupOperator": "AND"
}
Thanks in advance for your help.
try
output[i]['searchCriteria'] = createSearchCriteria(content)
instead of
output[i]['searchCriteria'] = [];
output[i]['searchCriteria'].push(createSearchCriteria(content))
I'm writing a function that simply loops through a Json schema. Let us say we have a simple json schema such as:
var foo = {
"description": "A car schema",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_rev": {
"type": "string"
},
"sources": {
"type": "object",
"properties": {
"mam": {
"type": "object",
"properties": {
"source_id": {
"type": [ "integer", "null" ]
},
"SOR": {
"type": ["boolean","null"]
}
}
},
"sas": {
"type": "object",
"properties": {
"source_id": {
"type": "string"
},
"SOR": {
"type": ["boolean","null"]
},
"CAR": {
"type": ["object","null"]
}
}
}
}
}
}
}
We're trying to collect the type of the key object from it. Here is function search for CAR type should return => "object"
parseObjectProperties = (obj)=> {
for (var k in obj) {
if(k === "CAR"){
console.log(_.values(obj[k])[0][0]) // When I do a console log like this prin the object value
return _.values(obj[k])[0][0] // but in return i get undefined
}
if ( _.isObject( obj[k]) && !_.isNil(obj[k])) {
return parseObjectProperties(obj[k])
}
}
}
parseObjectProperties(foo);
When I run it, the inner console.log(_.values(obj[k])[0][0]) shows the correct value: object
but if i run it
console.log(parseObjectProperties(foo));
I get
undefined
Why isn't the function properly returning the correct value => "object"?
Thank you!
I just re-wrote this as I didn't understand the logic you were using. Does this solve your problem?
FYI your object CAR, has a property named type whose value is an array that contains 2 values, "object" and "null" so you want to use obj[k].type[0] if you want to get "object" as the result.
const parseObjectProperties = (obj) => {
var result = null;
for (var k in obj)
if (k == "CAR") return obj[k].type[0];
else if (obj[k] instanceof Object)
result = parseObjectProperties(obj[k]);
return result;
}
var foo = {
"description": "A car schema",
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"_rev": {
"type": "string"
},
"sources": {
"type": "object",
"properties": {
"mam": {
"type": "object",
"properties": {
"source_id": {
"type": ["integer", "null"]
},
"SOR": {
"type": ["boolean", "null"]
}
}
},
"sas": {
"type": "object",
"properties": {
"source_id": {
"type": "string"
},
"SOR": {
"type": ["boolean", "null"]
},
"CAR": {
"type": ["object", "null"]
}
}
}
}
}
}
}
console.log(parseObjectProperties(foo));
I want to add conditionally required based on value of some other property.
'companyName' and 'companyAddress' should be required only if 'isInexperienced'
value is false.
Schema
{
"type": "object",
"properties": {
"previous_employment_section": {
"type": "array",
"items": {
"type": "object",
"properties": {
"companyAddress": {
"type": "string"
},
"companyName": {
"type": "string"
}
},
"if": {
"#/properties/isInexperienced": {
"const": false
}
},
"then": {
"required": [
"companyName",
"companyAddress"
]
}
}
},
"isInexperienced": {
"type": "boolean"
}
}
}
Data
{
"previous_employment_section": [],
"isInexperienced": true
}
I do not fully understand the intention of your original schema, but how about this one?
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"previous_employment_section": {
"type": "array",
"items": {
"type": "object",
"properties": {
"companyAddress": {
"type": "string"
},
"companyName": {
"type": "string"
}
}
}
},
"isInexperienced": {
"type": "boolean"
}
},
"if": {
"properties": {
"isInexperienced": {
"const": false
}
}
},
"then": {
"properties": {
"previous_employment_section": {
"items": {
"required": [
"companyName",
"companyAddress"
]
},
"minItems": 1
}
}
}
}
It is not possible. We need to have “if” on a higher level, “properties” can be nested. Leadpony's method can be used.
I'm trying to navigate through a complex nested JSON, however my attempt didn't get me too far as it keeps returning me the last index JSON.
This is how my Objects looks like, and trying to navigate through it and getting other objs/schemas that are in $ref.
Raw JSON
{
"type": "object",
"properties": {
"Id": {
"format": "int32",
"type": "integer"
},
"Status": {
"enum": [
"Preparing",
"AwaitingCompletion",
"Cancelled",
"Completed"
],
"type": "string"
},
"ExternalReference": {
"type": "string"
},
"Customer": {
"$ref": "#/definitions/Customer"
},
"OrderLineGroups": {
"type": "array",
"items": {
"$ref": "#/definitions/OrderLineGroup"
}
},
"Promotions": {
"type": "array",
"items": {
"$ref": "#/definitions/PromotionSummary"
}
},
"OriginatingSite": {
"type": "object",
"properties": {
"Id": {
"format": "int32",
"type": "integer"
},
"PropertyCode": {
"type": "string"
},
"StoreCode": {
"type": "string"
}
}
},
"CustomData": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "object"
}
}
}
}
}
In my code I have done for() and hasOwnProperty(), however my problem is that it doesn't give me all the JSON back even the condition is met (e.g if there's no type property), it only gives the last index or object that doesn't have type property. Also doesn't return me any of the objects if type property is array.
// Get property of #/definitions/obj
let prop = apiDefinition[splitResponse.split('/')[2]].properties;
console.log([prop])
var s = [apiDefinition[splitResponse.split('/')[2]].properties];
// Transform JS Object of #/definitions/Obj to JSON
var parentJSON = JSON.stringify(apiDefinition[splitResponse.split('/')[2]]);
for (var x in prop) {
if (prop.hasOwnProperty(x)) {
if (prop[x].type && prop[x].type === 'array') {
console.log('All type Array >> ', x);
let objKeyProp = apiDefinition[prop[x].items.$ref.split('/')[2]];
let objJsonStringified = JSON.stringify(objKeyProp);
let refString = '{"$ref"'+':' + '"' + prop[x].items.$ref + '"}';
this.compiledJson = JSON.parse(parentJSON.replace(refString, objJsonStringified));
} else if (!prop[x].type) {
console.log('all arrays >> ', x)
let objKeyProp = apiDefinition[prop[x].$ref.split('/')[2]];
let objJsonStringified = JSON.stringify(objKeyProp);
let refString = '{"$ref"'+':' + '"' + prop[x].$ref + '"}';
this.compiledJson = JSON.parse(parentJSON.replace(refString, objJsonStringified));
}
}
}
I have a JSON object at my disposal looking like this :
{
"Fields": [
{
"table": "catalogue",
"field": "Histo_Qtite",
"type": "STRING"
},
{
"table": "catalogue",
"field": "id_article",
"type": "STRING"
},
{
"table": "contact",
"field": "contact_email",
"type": "STRING"
},
{
"table": "contact",
"field": "contact_firestname",
"type": "STRING"
},
{
"table": "customer",
"field": "activity_type",
"type": "STRING"
},
{
"table": "customer",
"field": "adress",
"type": "STRING"
}
],
"Tables": [
{
"entity": "CATALOGUE",
"table": "catalogue"
},
{
"entity": "CLIENT",
"table": "customer"
},
{
"entity": "CONTACT",
"table": "contact"
}
]
}
I am trying to create a multidimensional array for every "Fields" objects base on the name of the table. To do so I experimented with javascript and it resulted in this code :
var objectPREFIX = "object_",
selectedObject = '',
objectArray = [],
objectImport = [],
OFImport = [],
TablesLength = jsonImport.Tables.length,
FieldsLength = jsonImport.Fields.length;
for (i = 0; i < FieldsLength; i++) {
selectedObject = objectPREFIX + jsonImport.Fields[i].table;
OFImport[selectedObject] = {
tableName : jsonImport.Fields[i].table,
FieldName : jsonImport.Fields[i].field,
fieldType : jsonImport.Fields[i].type
}
for (j = 0; j < TablesLength; j++) {
if(OFImport[selectedObject].tableName == jsonImport.Tables[j].table) {
objectImport.push(OFImport[selectedObject]);
objectArray[selectedObject] = OFImport[selectedObject];
}
}
}
console.log(objectArray);
The problem as I understand it is that OFImport[selectedObject] contain every object iteration of "Fields" and only display the last object in the console.
I would like to know how to make a comparison condition between "Fields" and "Tables" to get each iteration in separate arrays.
Here is a FIDDLE that demonstrates the issue (sorry if I have troubles articulating my explanation).
If I understand what your looking to do, which is have an array of tables, which has an array of fields, then I think you have your for loops backwards.
you need to loop your tables first, then add your fields like so:-
jsonImport = {
"Fields": [{
"table": "catalogue",
"field": "Histo_Qtite",
"type": "STRING"
}, {
"table": "catalogue",
"field": "id_article",
"type": "STRING"
}, {
"table": "contact",
"field": "contact_email",
"type": "STRING"
}, {
"table": "contact",
"field": "contact_firstname",
"type": "STRING"
}, {
"table": "customer",
"field": "activity_type",
"type": "STRING"
}, {
"table": "customer",
"field": "adress",
"type": "STRING"
}],
"Tables": [{
"entity": "CATALOGUE",
"table": "catalogue"
}, {
"entity": "CLIENT",
"table": "customer"
}, {
"entity": "CONTACT",
"table": "contact"
}]
}
var objectArray = [],
objectPREFIX = "object_",
selectedObject = '',
TablesLength = jsonImport.Tables.length,
FieldsLength = jsonImport.Fields.length;
for (i = 0; i < TablesLength; i++) {
selectedObject = objectPREFIX + jsonImport.Tables[i].table;
objectArray[selectedObject] = {
table: jsonImport.Tables[i].table,
entity: jsonImport.Tables[i].entity,
Fields: []
}
for (j = 0; j < FieldsLength; j++) {
if (jsonImport.Tables[i].table == jsonImport.Fields[j].table) {
objectArray[selectedObject].Fields.push({
"field": jsonImport.Fields[j].field,
"type": jsonImport.Fields[j].type
});
}
}
}
console.log(objectArray);
outputting:-