You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JsonSchema.Net.Generation基于带Category特性的类生成自定义JSON Schema

基于Category特性自定义JSON Schema生成方案

需求说明

在.NET 5.0环境下使用JsonSchema.Net.Generation组件,基于带有Category特性的类生成JSON Schema:

  • 标注Category("Student")的属性归到Student节点下
  • 标注Category("Staff")的属性归到Staff节点下
  • 标注Category("Common")的属性保留在根节点

示例类代码

using System.ComponentModel;
using Json.Schema.Generation;

[Title("Custom JSON Schema generation.")]
class School
{
    [DisplayName("Student")]
    [Category("Student")]
    [Description("School Schema generation test")]
    [Const(true)]
    public string StudentName { get; set; } = "XYZ";

    [Editable(true)]
    [Range(0, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    [Category("Student")]
    public int Id { get; set; } = 10;

    [Editable(false)]
    [DisplayName("ParentName")]
    [Display(Name = "PPhone", Description = "Testing", GroupName = "Student")]
    [Category("Student")]
    public string ParentName { get; set; }

    [DisplayName("ParentPhone")]
    [Category("Student")]
    public string ParentPhone { get; set; }

    [Editable(true)]
    [Category("Staff")]
    public string TeacherName { get; set; }

    [Editable(true)]
    [Range(0, 10000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    [DefaultValue(5000)]
    [Category("Staff")]
    public int Salary { get; set; }

    [ReadOnly(true)]
    [Category("Student")]
    public bool AvailingTransport { get; set; } = true;

    [ReadOnly(true)]
    [Category("Common")]
    public string Address { get; set; }

    [ReadOnly(true)]
    [Category("Common")]
    public string MobileNumber { get; set; }
}

默认生成的扁平化Schema

{
  "type": "object",
  "properties": {
    "StudentName": {
      "type": "string",
      "description": "School Schema generation test",
      "const": true
    },
    "Id": {
      "type": "integer"
    },
    "ParentName": {
      "type": "string"
    },
    "ParentPhone": {
      "type": "string"
    },
    "TeacherName": {
      "type": "string"
    },
    "Salary": {
      "type": "integer"
    },
    "AvailingTransport": {
      "type": "boolean",
      "readOnly": true
    },
    "Address": {
      "$ref": "#/$defs/string"
    },
    "MobileNumber": {
      "$ref": "#/$defs/string"
    }
  },
  "title": "Custom JSON Schema generation.",
  "$defs": {
    "string": {
      "type": "string",
      "readOnly": true
    }
  },
  "additionalProperties": false
}

期望的分组式Schema

{
  "type": "object",
  "properties": {
    "Student": {
      "type": "object",
      "properties": {
        "StudentName": {
          "type": "string",
          "description": "School Schema generation test",
          "const": true
        },
        "Id": {
          "type": "integer"
        },
        "ParentName": {
          "type": "string"
        },
        "ParentPhone": {
          "type": "string"
        },
        "AvailingTransport": {
          "type": "boolean",
          "readOnly": true
        }
      },
      "additionalProperties": false
    },
    "Staff": {
      "type": "object",
      "properties": {
        "TeacherName": {
          "type": "string"
        },
        "Salary": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "Address": {
      "$ref": "#/$defs/string"
    },
    "MobileNumber": {
      "$ref": "#/$defs/string"
    }
  },
  "title": "Custom JSON Schema generation.",
  "$defs": {
    "string": {
      "type": "string",
      "readOnly": true
    }
  },
  "additionalProperties": false
}

解决方案代码

核心思路

先通过默认方式生成扁平化Schema,再结合反射获取属性的Category特性,重新组织Schema的properties结构,将属性归类到对应节点。

完整实现代码

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Json.Schema;
using Json.Schema.Generation;
using System.Text.Json;
using System.ComponentModel;

class Program
{
    static void Main(string[] args)
    {
        // 1. 生成默认扁平化Schema
        var originalSchema = new JsonSchemaBuilder()
            .FromType<School>()
            .AdditionalProperties(false)
            .Build();

        // 2. 通过反射获取每个属性的Category
        var propertyCategoryMap = typeof(School)
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .ToDictionary(
                prop => prop.Name,
                prop => prop.GetCustomAttribute<CategoryAttribute>()?.Category ?? "Common"
            );

        // 3. 重新组织properties结构
        var rootProperties = new Dictionary<string, JsonSchema>();
        var studentProps = new Dictionary<string, JsonSchema>();
        var staffProps = new Dictionary<string, JsonSchema>();

        foreach (var (propName, propSchema) in originalSchema.Properties)
        {
            if (propertyCategoryMap.TryGetValue(propName, out var category))
            {
                switch (category)
                {
                    case "Student":
                        studentProps.Add(propName, propSchema);
                        break;
                    case "Staff":
                        staffProps.Add(propName, propSchema);
                        break;
                    default:
                        rootProperties.Add(propName, propSchema);
                        break;
                }
            }
            else
            {
                rootProperties.Add(propName, propSchema);
            }
        }

        // 4. 添加Student和Staff子节点
        if (studentProps.Any())
        {
            rootProperties.Add("Student", new JsonSchema
            {
                Type = JsonSchemaType.Object,
                Properties = studentProps,
                AdditionalProperties = false
            });
        }

        if (staffProps.Any())
        {
            rootProperties.Add("Staff", new JsonSchema
            {
                Type = JsonSchemaType.Object,
                Properties = staffProps,
                AdditionalProperties = false
            });
        }

        // 5. 创建自定义Schema
        var customSchema = new JsonSchema
        {
            Type = originalSchema.Type,
            Properties = rootProperties,
            Title = originalSchema.Title,
            Defs = originalSchema.Defs,
            AdditionalProperties = originalSchema.AdditionalProperties
        };

        // 6. 序列化输出
        var serializeOptions = new JsonSerializerOptions { WriteIndented = true };
        Console.WriteLine(JsonSerializer.Serialize(customSchema, serializeOptions));
    }
}

代码说明

  • 反射获取Category:通过Type.GetProperties遍历类属性,提取每个属性的CategoryAttribute值,建立属性名与分类的映射
  • 属性分组:遍历原Schema的properties,将属性分别放入Student、Staff或根节点的集合中
  • 构建子Schema:为Student和Staff分类创建独立的JsonSchema对象,设置为object类型并包含对应属性
  • 组装最终Schema:将分组后的属性集合替换原Schema的properties,保留原Schema的其他元数据(如title、$defs等)

内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:19:56