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

使用oneOf约束产品属性时无法限制非对应属性的问题

解决JSON Schema oneOf约束失效问题,确保产品属性严格匹配

问题背景

定义了3类产品,期望通过JSON Schema的oneOf关键字根据属性匹配对应产品,但当前Schema无法约束非对应产品的属性,导致不符合规则的JSON实例能通过验证。

原Schema尝试

{
  "type": "object",
  "required": [
    "type",
    "productId"
  ],
  "additionalProperties": false,
  "properties": {
    "productId": {
      "type": "string",
      "minLength": 1
    },
    "type": {
      "enum": ["product"]
    },
    "productInfo": {
      "type": "object",
      "additionalProperties": false,
      "required": [ "type", "gameMode"],
      "properties": {
        "type": {
          "enum": ["digital"]
        },
        "gameMode": {
          "type": "object",
          "oneOf": [
            { "$ref": "#/$defs/audioPlayer" },
            { "$ref": "#/$defs/multiPlayer" },
            { "$ref": "#/$defs/console" },
            { "$ref": "#/$defs/controller" }
          ]
        }
      }
    }
  },
  "$defs": {
    "audioPlayer": {
      "type": "object",
      "gameMode": {
        "enum": ["mp3", "wav"]
      }
    },
    "controller": {
      "type": "object",
      "properties": {
        "mode": {
          "enum": ["Retro","XboxElite" ]
        },
        "batteryLevel": { "type": "string" },
        "warranty": { "type": "string" },
        "tradeIn": { "type": "boolean" }
      }
    },
    "multiPlayer": {
      "type": "object",
      "properties": {
        "mode": {
          "enum": ["LiveXBox","FortNite"]                  
        },
        "signUp": {
          "type": "object",
          "properties": {
            "url": {   "type": "string" }
          }
        }
      }
    },
    "console": {
      "type": "object",
      "properties": {
        "mode": {
          "enum": ["single", "multi"]
        },
        "required": {
          "type": "boolean"
        }
      }
    }
  }
}

不符合预期的验证通过JSON

//This product has properties it shouldn't have
// signUp should be only allowed in multiplayer etc.      
{
  "type": "product",
  "productId": "wwwwww",
  "productInfo": {
    "type": "digital",
    "gameMode": {
      "mode": "mp3",
      "required": true,
      "signUp": "https://mmmmmmm.com",
      "warranty": "yes"
    }        
  }
}

正确示例

音频播放器(仅自身属性)

// Audio Player properties only
{
  "type": "product",
  "productId": "audio",
  "productInfo": {
    "type": "digital",
    "gameMode": {
      "mode": "mp3"  // or "wav"
    }        
  }
}

控制器(仅自身属性)

// Controller properties only
{
  "type": "product",
  "productId": "controller",
  "productInfo": {
    "type":"digital",
    "gameMode": {
      "mode": "Retro", // or XboxElite
      "batteryLevel": "high",
      "warranty": "yes",
      "tradeIn": true
    }        
  }
}

问题根源

  1. 所有产品定义($defs下的schema)未设置additionalProperties: false,导致额外属性不会被拦截;
  2. audioPlayer的定义存在语法错误,直接将gameMode作为顶级字段,而非放在properties下,导致该规则完全无效。

修正后的Schema

{
  "type": "object",
  "required": ["type", "productId"],
  "additionalProperties": false,
  "properties": {
    "productId": {
      "type": "string",
      "minLength": 1
    },
    "type": {
      "enum": ["product"]
    },
    "productInfo": {
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "gameMode"],
      "properties": {
        "type": {
          "enum": ["digital"]
        },
        "gameMode": {
          "type": "object",
          "oneOf": [
            {"$ref": "#/$defs/audioPlayer"},
            {"$ref": "#/$defs/multiPlayer"},
            {"$ref": "#/$defs/console"},
            {"$ref": "#/$defs/controller"}
          ]
        }
      }
    }
  },
  "$defs": {
    "audioPlayer": {
      "type": "object",
      "additionalProperties": false,
      "required": ["mode"],
      "properties": {
        "mode": {
          "enum": ["mp3", "wav"]
        }
      }
    },
    "controller": {
      "type": "object",
      "additionalProperties": false,
      "required": ["mode"],
      "properties": {
        "mode": {
          "enum": ["Retro", "XboxElite"]
        },
        "batteryLevel": {"type": "string"},
        "warranty": {"type": "string"},
        "tradeIn": {"type": "boolean"}
      }
    },
    "multiPlayer": {
      "type": "object",
      "additionalProperties": false,
      "required": ["mode"],
      "properties": {
        "mode": {
          "enum": ["LiveXBox", "FortNite"]
        },
        "signUp": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "url": {"type": "string"}
          }
        }
      }
    },
    "console": {
      "type": "object",
      "additionalProperties": false,
      "required": ["mode"],
      "properties": {
        "mode": {
          "enum": ["single", "multi"]
        },
        "required": {"type": "boolean"}
      }
    }
  }
}

修正说明

  • 给每个产品的schema添加additionalProperties: false,严格限制仅允许自身定义的属性;
  • 修正audioPlayer的结构,将原错误的gameMode字段改为mode并放入properties下,和其他产品字段名统一;
  • 为每个产品的mode字段添加required约束,确保产品类型标识明确;
  • 给multiPlayer下的signUp也添加additionalProperties: false,进一步约束嵌套对象的属性。

验证效果

修正后的Schema会拦截之前的错误示例(因包含非对应产品的required、signUp、warranty属性),而正确示例则能正常通过验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:36:24