Json Schema 中 $dynamicRef $dynamicAnchor 的解释(相对于 $ref 和 $anchor)
Explanation of $dynamicRef $dynamicAnchor in Json Schema (as opposed to $ref and $anchor)
有人可以解释 $dynamicRef keyword in JSON Schema
的目的吗
对于实际使用,请参阅 JSON 架构元架构本身。
它利用了 $dynamicAnchor 和 $dynamicRef。
Core schema 看起来像这样
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://json-schema.org/draft/2020-12/schema",
---- <snip>
"$dynamicAnchor": "meta", <-- first usage here
---- <snip>
"allOf": [
{"$ref": "meta/core"},
---- <snip>
]
---- <snip>
}
meta/core
(allOf
“包含”看起来像这样
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://json-schema.org/draft/2020-12/meta/core",
---- <snip>
"$dynamicAnchor": "meta", <-- second usage here
---- <snip>
"properties": {
---- <snip>
"$defs": {
"type": "object",
"additionalProperties": { "$dynamicRef": "#meta" } <-- reference here
---- <snip>
}
}
}
为什么这么复杂?它是如何工作的?即使我阅读了规范,我也无法真正理解它。
当扩展架构可能需要覆盖引用将解析到的位置时,使用动态引用。这在扩展递归模式(如元模式)中最常见,但也有其他用途。
这可能还没有意义,所以让我们从一个例子开始来说明为什么存在动态引用。此架构描述了一个递归树结构,其值为字符串。
{
"$id": "https://example.com/schemas/string-tree",
"type": "array",
"items": {
"anyOf": [
{ "type": "string" },
{ "$ref": "#" }
]
}
}
这是一个针对该架构进行验证的实例。
["a", ["b", "c", ["d"], "e"]]
现在,假设我们要扩展此架构,以便每个分支最多有两个节点。您可能想尝试以下架构。
{
"$id": "https://example.com/schemas/bounded-string-tree",
"$ref": "/schemas/string-tree",
"maxItems": 2
}
但是,maxItems
约束只适用于树的根。 /schemas/string-tree
中的递归引用仍然指向自身,不限制节点数
因此,["a", "b", "c"]
将按预期验证失败,因为存在三个节点。但是,["a", ["b", "c", "d"]]
不会失败,因为具有三个节点的分支仅针对 /schemas/string-tree
模式进行验证,而不是 /schemas/bounded-string-tree
模式。
因此,为了扩展递归模式,我需要一种方法允许扩展模式 (/schemas/bound-string-tree
) 更改扩展模式 (/schemas/string-tree
) 中的引用目标。动态引用提供了这种机制。
{
"$id": "https://example.com/schemas/base-string-tree",
"$dynamicAnchor": "branch",
"type": "array",
"items": {
"anyOf": [
{ "type": "string" },
{ "$dynamicRef": "#branch" }
]
}
}
在这种情况下,动态引用和锚点与常规引用和锚点的工作方式相同,只是现在可以根据需要通过扩展架构覆盖引用。如果没有扩展架构,它将转到此动态锚点。如果有一个扩展架构声明了一个匹配的动态锚点,它将覆盖这个更改动态引用解析到的位置。
{
"$id": "https://example.com/schemas/bounded-string-tree",
"$dynamicAnchor": "branch",
"$ref": "/schemas/base-string-tree",
"maxItems": 2
}
通过在 /schemas/bounded-string-tree
中设置“分支”动态锚点,我们可以有效地覆盖任何未来对“分支”的动态引用以解析到此位置。
现在,["a", ["b", "c", "d"]]
将无法按预期对 /schema/bounded-string-tree
进行验证。
您可能还听说过 JSON Schema 2019-09 中的 $recursiveRef
。这是动态引用的前身,仅对扩展递归模式有用,如本例所示。与递归引用不同,动态引用允许您在模式中设置多个扩展点。让我们进一步了解我们的示例,看看它为什么有用。
假设我们想要一个描述树的模式,但我们希望扩展模式能够覆盖树叶的模式。例如,我们可能想要一棵具有数字叶子节点而不是字符串的树。我们可以使用动态引用来允许叶被覆盖。
{
"$id": "https://example.com/schemas/base-tree",
"$dynamicAnchor": "branch",
"type": "array",
"items": {
"anyOf": [
{ "$dynamicRef": "#leaf" },
{ "$dynamicRef": "#branch" }
]
},
"$defs": {
"leaf": {
"$dynamicAnchor": "leaf",
"type": "string"
}
}
}
现在我们有两个扩展点,可以创建一个有界数树了。
{
"$id": "https://example.com/schemas/bounded-number-tree",
"$dynamicAnchor": "branch",
"$ref": "/schemas/base-tree",
"maxItems": 2,
"$defs": {
"leaf": {
"$dynamicAnchor": "leaf",
"type": "number"
}
}
}
动态引用还有一些更复杂的地方,我暂时不谈。希望这足以说明存在这种复杂机制的原因以及您希望何时使用它。我希望它也让它看起来不那么复杂。
有人可以解释 $dynamicRef keyword in JSON Schema
的目的吗对于实际使用,请参阅 JSON 架构元架构本身。
它利用了 $dynamicAnchor 和 $dynamicRef。
Core schema 看起来像这样
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://json-schema.org/draft/2020-12/schema",
---- <snip>
"$dynamicAnchor": "meta", <-- first usage here
---- <snip>
"allOf": [
{"$ref": "meta/core"},
---- <snip>
]
---- <snip>
}
meta/core
(allOf
“包含”看起来像这样
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://json-schema.org/draft/2020-12/meta/core",
---- <snip>
"$dynamicAnchor": "meta", <-- second usage here
---- <snip>
"properties": {
---- <snip>
"$defs": {
"type": "object",
"additionalProperties": { "$dynamicRef": "#meta" } <-- reference here
---- <snip>
}
}
}
为什么这么复杂?它是如何工作的?即使我阅读了规范,我也无法真正理解它。
当扩展架构可能需要覆盖引用将解析到的位置时,使用动态引用。这在扩展递归模式(如元模式)中最常见,但也有其他用途。
这可能还没有意义,所以让我们从一个例子开始来说明为什么存在动态引用。此架构描述了一个递归树结构,其值为字符串。
{
"$id": "https://example.com/schemas/string-tree",
"type": "array",
"items": {
"anyOf": [
{ "type": "string" },
{ "$ref": "#" }
]
}
}
这是一个针对该架构进行验证的实例。
["a", ["b", "c", ["d"], "e"]]
现在,假设我们要扩展此架构,以便每个分支最多有两个节点。您可能想尝试以下架构。
{
"$id": "https://example.com/schemas/bounded-string-tree",
"$ref": "/schemas/string-tree",
"maxItems": 2
}
但是,maxItems
约束只适用于树的根。 /schemas/string-tree
中的递归引用仍然指向自身,不限制节点数
因此,["a", "b", "c"]
将按预期验证失败,因为存在三个节点。但是,["a", ["b", "c", "d"]]
不会失败,因为具有三个节点的分支仅针对 /schemas/string-tree
模式进行验证,而不是 /schemas/bounded-string-tree
模式。
因此,为了扩展递归模式,我需要一种方法允许扩展模式 (/schemas/bound-string-tree
) 更改扩展模式 (/schemas/string-tree
) 中的引用目标。动态引用提供了这种机制。
{
"$id": "https://example.com/schemas/base-string-tree",
"$dynamicAnchor": "branch",
"type": "array",
"items": {
"anyOf": [
{ "type": "string" },
{ "$dynamicRef": "#branch" }
]
}
}
在这种情况下,动态引用和锚点与常规引用和锚点的工作方式相同,只是现在可以根据需要通过扩展架构覆盖引用。如果没有扩展架构,它将转到此动态锚点。如果有一个扩展架构声明了一个匹配的动态锚点,它将覆盖这个更改动态引用解析到的位置。
{
"$id": "https://example.com/schemas/bounded-string-tree",
"$dynamicAnchor": "branch",
"$ref": "/schemas/base-string-tree",
"maxItems": 2
}
通过在 /schemas/bounded-string-tree
中设置“分支”动态锚点,我们可以有效地覆盖任何未来对“分支”的动态引用以解析到此位置。
现在,["a", ["b", "c", "d"]]
将无法按预期对 /schema/bounded-string-tree
进行验证。
您可能还听说过 JSON Schema 2019-09 中的 $recursiveRef
。这是动态引用的前身,仅对扩展递归模式有用,如本例所示。与递归引用不同,动态引用允许您在模式中设置多个扩展点。让我们进一步了解我们的示例,看看它为什么有用。
假设我们想要一个描述树的模式,但我们希望扩展模式能够覆盖树叶的模式。例如,我们可能想要一棵具有数字叶子节点而不是字符串的树。我们可以使用动态引用来允许叶被覆盖。
{
"$id": "https://example.com/schemas/base-tree",
"$dynamicAnchor": "branch",
"type": "array",
"items": {
"anyOf": [
{ "$dynamicRef": "#leaf" },
{ "$dynamicRef": "#branch" }
]
},
"$defs": {
"leaf": {
"$dynamicAnchor": "leaf",
"type": "string"
}
}
}
现在我们有两个扩展点,可以创建一个有界数树了。
{
"$id": "https://example.com/schemas/bounded-number-tree",
"$dynamicAnchor": "branch",
"$ref": "/schemas/base-tree",
"maxItems": 2,
"$defs": {
"leaf": {
"$dynamicAnchor": "leaf",
"type": "number"
}
}
}
动态引用还有一些更复杂的地方,我暂时不谈。希望这足以说明存在这种复杂机制的原因以及您希望何时使用它。我希望它也让它看起来不那么复杂。