1

I am trying to get json schema from c# class file which has multiple classes.

I generated the c# class file (*.cs file) using xsd.exe and providing xml schema files (xsd files) (since main xsd has 2 imports so, has to give 2 other xsd files in same line in xsd.exe command)

ie, command to generate c# class file using xsd files

C:\Users\user1\jsonschema>xsd.exe /c main_1.xsd imported_1.xsd xml.xsd /o:C:\Users\user1\jsonschema\output\
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.3038]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\Users\user1\jsonschema\output\main_1_xml.cs'.

In main_1_xml.cs file, i can see multiple classes definition, now I need to convert this c# into json schema. I don't know how to do this part. Ideally am looking for one jsonschema outfile.

I admit am newbie c# so, don't know much of classes/serialization or other logic which converts c# classes into json format/schema.

Any help much appreciated.

[Edited: As per Zohar suggestion to inculde more details]

Basically have xsd file and using xsd.exe am generating c# class file. This class file has multiple sub classes/paritial class definitions. Now am trying to get this class definition into json schema format.

here is the c# class file content (have morethan 170 sub/parital classes definitions but simplicity kept only 2 :

using System.Xml.Serialization;
using System.Collections.Generic;
using Newtonsoft.Json;

// 
// This source code was auto-generated by xsd, Version=2.0.50727.3038.
// 

Filename : Program.cs

class Program // I have manually added this class and next line opening bracket for main class "Program"
{

    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://example.org/content/")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://example.org/content/2018/", IsNullable=false)]
    public partial class newItem : AnyItemType {

        private ContentMetadataAfDType contentMetaField;

        private AssertType[] assertField;

        private inlineRef[] inlineRefField;

        private object[] items1Field;

        private contentSet contentSetField;

        /// <remarks/>
        public ContentMetadataAfDType contentMeta {
            get {
                return this.contentMetaField;
            }
            set {
                this.contentMetaField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("assert")]
        public AssertType[] assert {
            get {
                return this.assertField;
            }
            set {
                this.assertField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("inlineRef")]
        public inlineRef[] inlineRef {
            get {
                return this.inlineRefField;
            }
            set {
                this.inlineRefField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("derivedFrom", typeof(derivedFrom))]
        [System.Xml.Serialization.XmlElementAttribute("derivedFromValue", typeof(derivedFromValue))]
        public object[] Items1 {
            get {
                return this.items1Field;
            }
            set {
                this.items1Field = value;
            }
        }

        /// <remarks/>
        public contentSet contentSet {
            get {
                return this.contentSetField;
            }
            set {
                this.contentSetField = value;
            }
        }
    }
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.example.org/content")]
    [System.Xml.Serialization.XmlRootAttribute("internal", Namespace="http://www.example.org/0809/content", IsNullable=false)]
    public partial class internalType {

        private object[] itemsField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("altId", typeof(altId), Namespace="http://example.org/content/2006-10-01/")]
        [System.Xml.Serialization.XmlElementAttribute("audience", typeof(AudienceType), Namespace="http://example.org/content/2006-10-01/")]
        [System.Xml.Serialization.XmlElementAttribute("contentMetaExtProperty", typeof(RSF_ContentMetaExtProperty_Flex2ExtPropType), Namespace="http://example.org/content/2006-10-01/")]
        [System.Xml.Serialization.XmlElementAttribute("itemMetaExtProperty", typeof(RSF_ItemMetaExtProperty_Flex2ExtPropType), Namespace="http://example.org/content/2006-10-01/")]
        [System.Xml.Serialization.XmlElementAttribute("subject", typeof(subject), Namespace="http://example.org/content/2006-10-01/")]
        public object[] Items {
            get {
                return this.itemsField;
            }
            set {
                this.itemsField = value;
            }
        }
    }
} // I have manually added this close bracket for main class "Program"

in the same Program.cs file, I have add one more class and include main method and logic to generate json output using Newtonsoft

class json
{
    /* below code to get the name of the classes from the namespace - was trying something
        public Type[] GetTypesInNamespace(Assembly assembly, string nameSpace)
        {
            return
              assembly.GetTypes()
                      .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
                      .ToArray();
        }
    */
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Program Generation = new Program();
            var schemaGenerator = new Newtonsoft.Json.Schema.Generation.JSchemaGenerator();
            schemaGenerator.GenerationProviders.Add(new Newtonsoft.Json.Schema.Generation.StringEnumGenerationProvider());

            // if we give just main class name "Program, then in the out we get just 3 lines json format with type value as object"
            var schema = schemaGenerator.Generate(typeof(JsonSchema.Program));

            // if we pass-in main class and it's sub class name, then we get output of that sub class content as json format
            //var schema = schemaGenerator.Generate(typeof(JsonSchema.Program.newsItem));
            //Console.WriteLine(schema);

            File.WriteAllText(@"Program1.json", schema.ToString());

            //Program program = new Program();
            //string strResultJson = JsonConvert.SerializeObject(program);
            //File.WriteAllText(@"Program.json", strResultJson);
            //Console.WriteLine("Worked!");


        /*
            logic to get the sub classnames and loop through inorder to all sub classes content as single json schema in one file

            List<Type> theList = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "JsonSchema").ToList();
            Console.WriteLine(theList);
            //File.WriteAllText(@"Classnames.json", theList.ToString());
            for (int i = 0; i < theList.Count; i++)
            {
                Console.WriteLine(theList[i].Name); // this gives full list of class names

                File.WriteAllText(@"Classnames.json", theList[i].Name); // this writes only last classname, guess I need to figureout how to append
                //File.WriteAllLines(@"Classnames.json", i);
            }
        */

        }
    }
HULK
  • 89
  • 1
  • 14
  • You can use [Json.NET Schema](https://www.newtonsoft.com/jsonschema) to generate json schema from c# types. – Zohar Peled Mar 02 '19 at 13:55
  • thanks @ZoharPeled. Can we generate json schema from *.cs file and that too one jsonschema file even though *.cs has multiple classes defined. do we have any example or reference to do this. – HULK Mar 02 '19 at 16:12
  • You don't need the enclosing type (though this is not the problem). I'm attempting to recreate the problem now. – Zohar Peled Mar 05 '19 at 06:23
  • Well, apparently the enclosing type was the problem... I've edited my answer. – Zohar Peled Mar 05 '19 at 06:50
  • Perfect Zohar, looks like your suggestion worked. ie, putting all the xsd.exe generated types into another class and then call that class name in your code as "mainclassname". Is there a way we can just simply get all the types and create new class. am thinking more automatic way so, I don't have to create another class with all types or is it possible to just pass-in the xsd.exe generated *.cs file (which has all types) to your code. – HULK Mar 05 '19 at 07:15
  • You could create a schema for each generated type individually by looping over the types and generating a schema for each one, but if you want to generate one schema for all of them you have to have a class holding them as properties. Of course, this could also be automated using reflection - and even compile at run time. – Zohar Peled Mar 05 '19 at 07:54
  • hmm ok, so when you say "to generate one schema for all of then you have to have a class holding them as properties" what does this mean. please correct am wrong here, you are saying, we should have one *.cs which will have all the types defined separately. if so, that is what am having in *.cs. about reflection, if I get the types names, can I create get/set method for each and put them under one class/type using for loop. sorry to ask this but am very new c# concepts. – HULK Mar 05 '19 at 08:05
  • No, classes can be on different files, even in different projects, but you will need one class to hold them all as properties just like in my answer. If you want to automate the generation of this class you could use c# it would need to use reflection to generate it. – Zohar Peled Mar 05 '19 at 08:33
  • hmm, ok, still need to this logic. do you have reference or example on reflection which you said to generate it using c#. so i can give it a try. am trying this at the moment ie,List theList = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "JsonSchema").ToList(); for (int i = 0; i < theList.Count; i++) { Console.WriteLine(theList[i].Name);File.WriteAllText(@"Classnames.json", theList[i].Name);} but this puts only last or 1 type name in Classnames.json. am just trying to get class/types name so, can create new class with get/set as you mentioned earlier. – HULK Mar 05 '19 at 08:45
  • That's a different question already - but you are in the right direction. Instead of writing the type names to the console you can append them to a string builder `sb.Append("public ").Append(typeName).Append(" ").Append(typeName).AppendLine(" {get;set;}");` - that would create the code - and then you can [compile that into a class](https://www.google.com/search?q=how+to+compile+c%23+code+at+runtime&rlz=1C1LENP_iwIL718IL718&oq=how+to+compile+c%23+in+runtim&aqs=chrome.1.69i57j0.11295j0j7&sourceid=chrome&ie=UTF-8) (Which is something I've never done so I can't recommend the best way). – Zohar Peled Mar 05 '19 at 09:12
  • Thanks Zohar for letting me know about StringBuilder sb. I am able to create seperate *.cs file which will have all the types names with required get/set. ie, List theList = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "JsonSchema").ToList();System.Text.StringBuilder sb = new StringBuilder();for (int i = 0; i < theList.Count; i++){sb.Append("public ").Append(theList[i].Name).Append(" ").Append(theList[i].Name).AppendLine(" { get; set; }");System.IO.File.WriteAllText(@"Pgm.cs", sb.ToString());} now how to pass this new file in your code inplace of mainclass name. – HULK Mar 05 '19 at 10:58
  • As I said, that should be in a separate question. We already extended this discussions longer that it should have been - but here are a couple of links that might help: https://stackoverflow.com/questions/3862226/how-to-dynamically-create-a-class-in-c and https://stackoverflow.com/questions/906483/how-to-get-classes-and-methods-from-a-cs-file-using-reflections-in-c – Zohar Peled Mar 05 '19 at 11:48
  • thanks Zohar. Will ask my query as different question. Thanks Again – HULK Mar 05 '19 at 11:57

1 Answers1

1

It's really a very simple process:

You create an instance of JSchemaGenerator,
(optional) add a new instance of StringEnumGenerationProvider to it's GenerationProviders collection,
and generate the schema from the c# type*:

var schemaGenerator = new Newtonsoft.Json.Schema.Generation.JSchemaGenerator();
schemaGenerator.GenerationProviders.Add(new Newtonsoft.Json.Schema.Generation.StringEnumGenerationProvider());
var schema = schemaGenerator.Generate(typeof(YourMainClassHere));

*Don't forget to change YourMainClassHere to the actual name of the class.

This will generate the schema for the main class as well as any type of it's properties.

Update
Instead of enclosing all xsd-generated types inside a class, try creating a class that will use all these types as properties:

class Program 
{
    public newItem NewItem { get; set; }
    public internalType InternalType { get; set; }
    public AssertType AssertType { get; set; }
    // Whatevet more types you need
}

Then, when you generate a schema for the Program class, it will also contain all the properties if the xsd generated types as well.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • Hi Zohar, Sorry It took some time to setup Visual Studio 2017, I have added your code and reference required Newtsoft.json into the project. but am getting this error ie, Program.cs(23781,62,23781,72): error CS0234: The type or namespace name 'Generation' does not exist in the namespace 'Newtonsoft.Json.Schema' (are you missing an assembly reference?) Should I create "Generation.cs" and if yes what should be there in that file. – HULK Mar 04 '19 at 12:34
  • I'm using `Newtonsoft.Json` and `Newtonsoft.Json.Schema` in my project. The schema was once a part of the Newtonsoft.Json dll but was separated in later versions. Perhaps that's the problem in your case. Try to install Newtonsoft.Json.Schema as well. – Zohar Peled Mar 04 '19 at 12:39
  • yes, after installing "Newtonsoft.Json.Schema" I don't see that error anymore. Now how to see the generated json output or is that way we can redirect the variable "schema" to a output file ? I tried but "schema" is not of string type it won;t work. – HULK Mar 04 '19 at 13:14
  • `schema.ToString()` will return a string representation of the json schema so that you can save it as a file – Zohar Peled Mar 04 '19 at 13:43
  • thanks Zohar. after adding a line to write the result to file ie, "File.WriteAllText(@"Res.json", schema.ToString());". I can see in Res.json file only { "type": "object" } even thou gave mainclassname. I was expecting to see full mainclass content as/in json format. but when I tried with : var schema = schemaGenerator.Generate(typeof(JsonSchema.Program.newItem)); var schema = //schemaGenerator.Generate(typeof(JsonSchema.Program)); then Res.json has output in json format which is of only newItem (parital class within mainclass Program) – HULK Mar 04 '19 at 13:54
  • [Perhaps a link to official documentation would help...](https://www.newtonsoft.com/jsonschema/help/html/GeneratingSchemas.htm) – Zohar Peled Mar 04 '19 at 14:23
  • Thanks. Still not able to get around full class content into json by just giving mainclassName. I thought of getting all classnames and somehow loop thru each class and write the json format into same file. ie, var theList = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "JsonSchema").ToList(); Console.WriteLine(theList); – HULK Mar 04 '19 at 14:52
  • It's impossible to debug without seeing the code. If you could edit your question to include the code you currently have, it would help us help you. – Zohar Peled Mar 04 '19 at 15:39
  • updated the main question with more details and what am trying to get. please have a look. thanks – HULK Mar 04 '19 at 16:40