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

如何在非根子Schema中正确实现JSON Schema递归?

如何正确设计包含子Schema递归的JSON Schema?

问题描述

我正在设计一个包含递归元素的JSON Schema,递归元素不在根节点,而是位于子Schema中。原Schema代码如下:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "http://example.org/json-schema/struct.schema.json",
    "type": "array",
    "items": {
        "title": "Structure",
        "type": "object",
        "properties": {
            "id": {
                "title": "ID",
                "type": "string"
            },
            "label": {
                "title": "Label",
                "type": "string"
            },
            "children": {
                "$anchor": "children",
                "title": "Children",
                "type": "array",
                "items": {
                    "title": "Structure Item",
                    "type": "object",
                    "properties": {
                        "id": {
                            "title": "ID",
                            "type": "string"
                        },
                        "href": {
                            "title": "Reference",
                            "type": "string"
                        },
                        "label": {
                            "title": "Structure Item Label",
                            "type": "string"
                        },
                        "sort_label": {
                            "title": "Sort Label",
                            "type": "string"
                        },
                        "children": {"$ref": "children"}
                    }
                },
                "anyOf": [
                    {"required": ["id", "href"]},
                    {"required": ["id", "children"]}
                ]
            }
        },
        "required": ["id", "label", "children"]
    }
}

编译该Schema时,在线验证器报错,使用python-fastjsonschema时会陷入循环。尝试过用"$ref": "#/items/properties/children"引用非命名锚点,Schema能编译但验证时报错。

问题分析

  1. 逻辑位置错误:原Schema中anyOf规则被放在了children数组的Schema下,但实际这个规则是约束数组内的每个结构项(Structure Item),而非数组本身。
  2. 递归引用混淆:用$anchor绑定的是children数组的Schema,但递归需要的是结构项的Schema,导致引用目标错误,进而引发循环或验证失败。
  3. 工具兼容性:部分JSON Schema工具对嵌套锚点的递归支持不佳,而使用$defs定义可复用Schema是更标准、兼容性更好的方式。

正确的Schema写法

将可复用的递归结构项抽离到$defs中,明确递归引用的目标,同时修正规则的位置:

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "http://example.org/json-schema/struct.schema.json",
    "type": "array",
    "items": {
        "title": "Structure",
        "type": "object",
        "properties": {
            "id": {
                "title": "ID",
                "type": "string"
            },
            "label": {
                "title": "Label",
                "type": "string"
            },
            "children": {
                "title": "Children",
                "type": "array",
                "items": {"$ref": "#/$defs/StructureItem"}
            }
        },
        "required": ["id", "label", "children"]
    },
    "$defs": {
        "StructureItem": {
            "title": "Structure Item",
            "type": "object",
            "properties": {
                "id": {
                    "title": "ID",
                    "type": "string"
                },
                "href": {
                    "title": "Reference",
                    "type": "string"
                },
                "label": {
                    "title": "Structure Item Label",
                    "type": "string"
                },
                "sort_label": {
                    "title": "Sort Label",
                    "type": "string"
                },
                "children": {
                    "title": "Children",
                    "type": "array",
                    "items": {"$ref": "#/$defs/StructureItem"}
                }
            },
            "anyOf": [
                {"required": ["id", "href"]},
                {"required": ["id", "children"]}
            ]
        }
    }
}

关键调整说明

  • 抽离递归结构:把Structure Item的Schema放到$defs中,作为独立的可复用单元,递归时直接引用这个定义,避免混淆。
  • 修正规则位置:将anyOf约束移到StructureItem下,确保每个结构项都满足"带链接"或"带子节点"的要求。
  • 清晰的引用路径:使用#/$defs/StructureItem这种明确的JSON Pointer引用,兼容性更强,不会出现锚点绑定错误的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:38:21