【问题标题】:Explanation of $dynamicRef $dynamicAnchor in Json Schema (as opposed to $ref and $anchor)Json Schema 中 $dynamicRef $dynamicAnchor 的解释(相对于 $ref 和 $anchor)
【发布时间】:2021-10-26 19:09:11
【问题描述】:

谁能解释$dynamicRef keyword in JSON Schema的目的

有关实际使用,请参阅 JSON Schema 元模式本身。

它利用了 $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>
        }
    }
}

为什么这么复杂?它是如何工作的?即使我阅读了规范,我也无法真正理解它。

【问题讨论】:

    标签: jsonschema


    【解决方案1】:

    当扩展架构可能需要覆盖引用将解析到的位置时,使用动态引用。这在扩展递归模式(如元模式)中最常见,但也有其他用途。

    这可能还没有意义,所以让我们从一个例子开始说明为什么存在动态引用。此模式描述了一个递归树结构,其值为字符串。

    {
      "$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": {
        "$dynamicAnchor": "leaf",
        "type": "number"
      }
    }
    

    动态引用还有一些更复杂的地方,我暂时不会讨论。希望这足以说明为什么存在这种复杂的机制以及何时想要使用它。我希望它也让它看起来不那么复杂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-09
      • 2022-01-23
      • 2014-09-16
      • 2021-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      相关资源
      最近更新 更多