Validate each JSON node with different JSON schema












0















Im trying to make a system monitor, which is highly customisable by user. This customization is achieved by using JSON file for modeling look of system monitor. The JSON could look like this.



{
"_": "WINDOW",
"name": "myWindow",
"children": [
{
"_": "CPU",
"name": "cpuMonitor",
"freq_Unit": "MHZ"
},
{
"_": "NETWORK",
"name": "network",
"unit": "Kb/s"
},
{
"_": "DISK",
"name": "disk"
}
],
"background": "red"
}


As you can see, each object coresponds to this schema.



{
"$schema": "http://json-schema.org/draft-07/schema#",
"name":"Component",
"type": "object",
"properties":{
"_": {
"type": "string"
},
"name":{
"type":"string"
},
"childern":{
"type":"array"
}
},

"required": ["_","name"]
}


But each component has also its own schema definition. I'd like to parse whole JSON and validate each node for different schema (first if its component and then to its corresponding schema).



I had look at rapidJson and other libraries, but I didnt find solution for validating nodes for different schema. Do you know any library which could do that? Or is it even possible to validate JSON in this way?



All feedback on how to solve this will be appreciated.



Edit: Corrected schema :(










share|improve this question

























  • This question has nothing to do with C++.

    – Ulrich Eckhardt
    Nov 25 '18 at 14:29
















0















Im trying to make a system monitor, which is highly customisable by user. This customization is achieved by using JSON file for modeling look of system monitor. The JSON could look like this.



{
"_": "WINDOW",
"name": "myWindow",
"children": [
{
"_": "CPU",
"name": "cpuMonitor",
"freq_Unit": "MHZ"
},
{
"_": "NETWORK",
"name": "network",
"unit": "Kb/s"
},
{
"_": "DISK",
"name": "disk"
}
],
"background": "red"
}


As you can see, each object coresponds to this schema.



{
"$schema": "http://json-schema.org/draft-07/schema#",
"name":"Component",
"type": "object",
"properties":{
"_": {
"type": "string"
},
"name":{
"type":"string"
},
"childern":{
"type":"array"
}
},

"required": ["_","name"]
}


But each component has also its own schema definition. I'd like to parse whole JSON and validate each node for different schema (first if its component and then to its corresponding schema).



I had look at rapidJson and other libraries, but I didnt find solution for validating nodes for different schema. Do you know any library which could do that? Or is it even possible to validate JSON in this way?



All feedback on how to solve this will be appreciated.



Edit: Corrected schema :(










share|improve this question

























  • This question has nothing to do with C++.

    – Ulrich Eckhardt
    Nov 25 '18 at 14:29














0












0








0








Im trying to make a system monitor, which is highly customisable by user. This customization is achieved by using JSON file for modeling look of system monitor. The JSON could look like this.



{
"_": "WINDOW",
"name": "myWindow",
"children": [
{
"_": "CPU",
"name": "cpuMonitor",
"freq_Unit": "MHZ"
},
{
"_": "NETWORK",
"name": "network",
"unit": "Kb/s"
},
{
"_": "DISK",
"name": "disk"
}
],
"background": "red"
}


As you can see, each object coresponds to this schema.



{
"$schema": "http://json-schema.org/draft-07/schema#",
"name":"Component",
"type": "object",
"properties":{
"_": {
"type": "string"
},
"name":{
"type":"string"
},
"childern":{
"type":"array"
}
},

"required": ["_","name"]
}


But each component has also its own schema definition. I'd like to parse whole JSON and validate each node for different schema (first if its component and then to its corresponding schema).



I had look at rapidJson and other libraries, but I didnt find solution for validating nodes for different schema. Do you know any library which could do that? Or is it even possible to validate JSON in this way?



All feedback on how to solve this will be appreciated.



Edit: Corrected schema :(










share|improve this question
















Im trying to make a system monitor, which is highly customisable by user. This customization is achieved by using JSON file for modeling look of system monitor. The JSON could look like this.



{
"_": "WINDOW",
"name": "myWindow",
"children": [
{
"_": "CPU",
"name": "cpuMonitor",
"freq_Unit": "MHZ"
},
{
"_": "NETWORK",
"name": "network",
"unit": "Kb/s"
},
{
"_": "DISK",
"name": "disk"
}
],
"background": "red"
}


As you can see, each object coresponds to this schema.



{
"$schema": "http://json-schema.org/draft-07/schema#",
"name":"Component",
"type": "object",
"properties":{
"_": {
"type": "string"
},
"name":{
"type":"string"
},
"childern":{
"type":"array"
}
},

"required": ["_","name"]
}


But each component has also its own schema definition. I'd like to parse whole JSON and validate each node for different schema (first if its component and then to its corresponding schema).



I had look at rapidJson and other libraries, but I didnt find solution for validating nodes for different schema. Do you know any library which could do that? Or is it even possible to validate JSON in this way?



All feedback on how to solve this will be appreciated.



Edit: Corrected schema :(







json jsonschema rapidjson






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 25 '18 at 14:28









Ulrich Eckhardt

12.7k11738




12.7k11738










asked Nov 25 '18 at 13:02









KwanKwan

11




11













  • This question has nothing to do with C++.

    – Ulrich Eckhardt
    Nov 25 '18 at 14:29



















  • This question has nothing to do with C++.

    – Ulrich Eckhardt
    Nov 25 '18 at 14:29

















This question has nothing to do with C++.

– Ulrich Eckhardt
Nov 25 '18 at 14:29





This question has nothing to do with C++.

– Ulrich Eckhardt
Nov 25 '18 at 14:29












2 Answers
2






active

oldest

votes


















1














There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.



Notes:




  • I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.

  • A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.






share|improve this answer































    1














    In addition to Ulrich's answer, here's an example of what I'd do:



    {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Component",
    "type": "object",
    "definitions": {
    "base": {
    "properties": {
    "name": { "type": "string" },
    "children": {
    "type": "array",
    "items": { "$ref": "#" }
    }
    },
    "required": [ "_", "name" ]
    },
    "cpu": {
    "properties": {
    "_": { "const": "CPU" },
    "freq_Unit": "MHZ"
    }
    },
    "network": {
    "properties": {
    "_": { "const": "NETWORK" },
    "unit": "Kb/s"
    }
    },
    "disk": {
    "properties": {
    "_": { "const": "DISK" }
    }
    },
    "window": {
    "properties": {
    "_": { "const": "WINDOW" },
    "background": { "enum": [ "red", "orange", "yellow", ... ] }
    }
    }
    },
    "allOf": [
    { "$ref": "#/definitions/base" },
    {
    "oneOf": [
    { "$ref": "#/definitions/cpu" },
    { "$ref": "#/definitions/network" },
    { "$ref": "#/definitions/disk" },
    { "$ref": "#/definitions/window" }
    ]
    }
    ]
    }


    First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.



    (Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)



    Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.



    This will get you where you want to be.



    To take it further, there are two more things you can do:




    1. Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).

    2. Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467714%2fvalidate-each-json-node-with-different-json-schema%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      1














      There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.



      Notes:




      • I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.

      • A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.






      share|improve this answer




























        1














        There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.



        Notes:




        • I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.

        • A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.






        share|improve this answer


























          1












          1








          1







          There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.



          Notes:




          • I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.

          • A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.






          share|improve this answer













          There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.



          Notes:




          • I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.

          • A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 25 '18 at 14:39









          Ulrich EckhardtUlrich Eckhardt

          12.7k11738




          12.7k11738

























              1














              In addition to Ulrich's answer, here's an example of what I'd do:



              {
              "$schema": "http://json-schema.org/draft-07/schema#",
              "title": "Component",
              "type": "object",
              "definitions": {
              "base": {
              "properties": {
              "name": { "type": "string" },
              "children": {
              "type": "array",
              "items": { "$ref": "#" }
              }
              },
              "required": [ "_", "name" ]
              },
              "cpu": {
              "properties": {
              "_": { "const": "CPU" },
              "freq_Unit": "MHZ"
              }
              },
              "network": {
              "properties": {
              "_": { "const": "NETWORK" },
              "unit": "Kb/s"
              }
              },
              "disk": {
              "properties": {
              "_": { "const": "DISK" }
              }
              },
              "window": {
              "properties": {
              "_": { "const": "WINDOW" },
              "background": { "enum": [ "red", "orange", "yellow", ... ] }
              }
              }
              },
              "allOf": [
              { "$ref": "#/definitions/base" },
              {
              "oneOf": [
              { "$ref": "#/definitions/cpu" },
              { "$ref": "#/definitions/network" },
              { "$ref": "#/definitions/disk" },
              { "$ref": "#/definitions/window" }
              ]
              }
              ]
              }


              First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.



              (Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)



              Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.



              This will get you where you want to be.



              To take it further, there are two more things you can do:




              1. Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).

              2. Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.






              share|improve this answer




























                1














                In addition to Ulrich's answer, here's an example of what I'd do:



                {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "title": "Component",
                "type": "object",
                "definitions": {
                "base": {
                "properties": {
                "name": { "type": "string" },
                "children": {
                "type": "array",
                "items": { "$ref": "#" }
                }
                },
                "required": [ "_", "name" ]
                },
                "cpu": {
                "properties": {
                "_": { "const": "CPU" },
                "freq_Unit": "MHZ"
                }
                },
                "network": {
                "properties": {
                "_": { "const": "NETWORK" },
                "unit": "Kb/s"
                }
                },
                "disk": {
                "properties": {
                "_": { "const": "DISK" }
                }
                },
                "window": {
                "properties": {
                "_": { "const": "WINDOW" },
                "background": { "enum": [ "red", "orange", "yellow", ... ] }
                }
                }
                },
                "allOf": [
                { "$ref": "#/definitions/base" },
                {
                "oneOf": [
                { "$ref": "#/definitions/cpu" },
                { "$ref": "#/definitions/network" },
                { "$ref": "#/definitions/disk" },
                { "$ref": "#/definitions/window" }
                ]
                }
                ]
                }


                First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.



                (Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)



                Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.



                This will get you where you want to be.



                To take it further, there are two more things you can do:




                1. Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).

                2. Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.






                share|improve this answer


























                  1












                  1








                  1







                  In addition to Ulrich's answer, here's an example of what I'd do:



                  {
                  "$schema": "http://json-schema.org/draft-07/schema#",
                  "title": "Component",
                  "type": "object",
                  "definitions": {
                  "base": {
                  "properties": {
                  "name": { "type": "string" },
                  "children": {
                  "type": "array",
                  "items": { "$ref": "#" }
                  }
                  },
                  "required": [ "_", "name" ]
                  },
                  "cpu": {
                  "properties": {
                  "_": { "const": "CPU" },
                  "freq_Unit": "MHZ"
                  }
                  },
                  "network": {
                  "properties": {
                  "_": { "const": "NETWORK" },
                  "unit": "Kb/s"
                  }
                  },
                  "disk": {
                  "properties": {
                  "_": { "const": "DISK" }
                  }
                  },
                  "window": {
                  "properties": {
                  "_": { "const": "WINDOW" },
                  "background": { "enum": [ "red", "orange", "yellow", ... ] }
                  }
                  }
                  },
                  "allOf": [
                  { "$ref": "#/definitions/base" },
                  {
                  "oneOf": [
                  { "$ref": "#/definitions/cpu" },
                  { "$ref": "#/definitions/network" },
                  { "$ref": "#/definitions/disk" },
                  { "$ref": "#/definitions/window" }
                  ]
                  }
                  ]
                  }


                  First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.



                  (Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)



                  Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.



                  This will get you where you want to be.



                  To take it further, there are two more things you can do:




                  1. Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).

                  2. Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.






                  share|improve this answer













                  In addition to Ulrich's answer, here's an example of what I'd do:



                  {
                  "$schema": "http://json-schema.org/draft-07/schema#",
                  "title": "Component",
                  "type": "object",
                  "definitions": {
                  "base": {
                  "properties": {
                  "name": { "type": "string" },
                  "children": {
                  "type": "array",
                  "items": { "$ref": "#" }
                  }
                  },
                  "required": [ "_", "name" ]
                  },
                  "cpu": {
                  "properties": {
                  "_": { "const": "CPU" },
                  "freq_Unit": "MHZ"
                  }
                  },
                  "network": {
                  "properties": {
                  "_": { "const": "NETWORK" },
                  "unit": "Kb/s"
                  }
                  },
                  "disk": {
                  "properties": {
                  "_": { "const": "DISK" }
                  }
                  },
                  "window": {
                  "properties": {
                  "_": { "const": "WINDOW" },
                  "background": { "enum": [ "red", "orange", "yellow", ... ] }
                  }
                  }
                  },
                  "allOf": [
                  { "$ref": "#/definitions/base" },
                  {
                  "oneOf": [
                  { "$ref": "#/definitions/cpu" },
                  { "$ref": "#/definitions/network" },
                  { "$ref": "#/definitions/disk" },
                  { "$ref": "#/definitions/window" }
                  ]
                  }
                  ]
                  }


                  First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.



                  (Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)



                  Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.



                  This will get you where you want to be.



                  To take it further, there are two more things you can do:




                  1. Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).

                  2. Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 26 '18 at 2:24









                  gregsdennisgregsdennis

                  2,35912547




                  2,35912547






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467714%2fvalidate-each-json-node-with-different-json-schema%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Feedback on college project

                      Futebolista

                      Albești (Vaslui)