【问题标题】:JSON Schema: multiple $ref get removed when reading file with requireJSON Schema:使用 require 读取文件时删除了多个 $ref
【发布时间】:2015-06-23 14:02:24
【问题描述】:

我有一个定义多个属性的 json 架构。我已将 2 个属性移至定义并引用它们。我这样做是因为我想将它们组合在一起并以通用的方式对这些属性进行一些测试。这工作正常,所有 json 数据都像以前一样处理。

但是,我注意到当我将 json 模式文件读入我的 javascript 文件时,我只看到最后一个 $ref。我不知道这是什么原因。我真的需要知道所有引用的属性。

这是我的 json 架构的 sn-p(在文件 schemas/schema1.json 中):

{
    "type": "object",
    "properties": {
         "$ref": "#/definitions/groupedProperties/property1",
         "$ref": "#/definitions/groupedProperties/property2"
    },
    "definitions": {
        "groupedProperties": {
            "type": "object",
            "properties": {
                "property1": {
                    "type": "string"
                },
                "property2": {
                    "type": "string"
                }
            }
        }
    }
}

然后我像这样将它读入我的 js 文件中(在文件 test.js 中):

var schemas = requireDir('./schemas')
for (var prop in schemas['schema1'].properties) {
    console.log(prop)
}

当我从我的 js 文件中迭代架构中的属性时,我只能看到一个 $ref。我想这是因为它认为属性名称是 '$ref' 并且只能有唯一的名称。是否有某种方法需要我要求这个文件,以便第一个 $ref 不会被破坏?

编辑:我的语法没有通过 json 模式验证器,虽然我不知道为什么,所以我没有为此苦苦挣扎,而是决定做一些不同的事情。我想要的只是一种对某些属性进行分组的方法,所以我将属性放回主模式中,并将定义更改为只是组成组的属性名称的枚举。所以现在我的架构看起来像:

{
    "type": "object",
    "properties": {
        "property1": {
            "type": "string"
        },
        "property2": {
            "type": "string"
        }
    },
    "definitions": {
        "groupedProperties": {
            "enum": ["property1", "property2"]
        }
    }
}

然后在我的js文件中:

var myGroup = (schema.definitions ? schema.definitions.groupedProperties : [])
console.log(myGroup.enum) // [ 'property1', 'property2' ]

【问题讨论】:

    标签: javascript jsonschema


    【解决方案1】:

    你如何引用你的定义有很多问题。

    ###JSON 对象不能有重复的属性 JSON 或 JavaScript 对象中的所有属性都是唯一的。第二个将覆盖第一个。考虑访问属性的语法以了解原因。当您将 JSON 读入 JavaScript 对象时,您可以尝试使用 schema.properties['$ref'] 访问 $ref 属性。如果有两个,你会得到哪一个(或两个)? JavaScript 没有机制来区分,因为它是不允许的。

    ###$ref 必须独立 在对象中使用$ref 时,它必须是该对象中的唯一属性。所有其他属性将被忽略。这只是拥有两个$refs 不起作用的另一个原因。

    JSON 引用对象中除 "$ref" 之外的任何成员都应为 忽略。

    ###$ref 不应在properties 中使用 $ref 只能用于引用模式。在这种情况下,properties 关键字使用$ref,它是一个具有模式值的对象。在 JSON Schema 或 JSON Reference 的文档中没有明确禁止以这种方式使用 $ref,但它不是惯用的 JSON Schema,因此大多数验证器都不支持。即使您使用的验证器确实支持这样的引用,也应该避免这样做,因为它从来都不是必需的,并且会使架构混乱且难以维护。

    ###您的 JSON 指针错误 您的 JSON 指针实际上并不指向您定义的模式。正确的指针是#/definitions/groupedProperties/properties/property1

    ###可能的解决方案 这就是你想要做的。

    {
       "type": "object",
       "properties": {
            "property1": { "$ref": "#/definitions/groupedProperties/properties/property1" },
            "property2": { "$ref": "#/definitions/groupedProperties/properties/property2" }
       },
       "definitions": {
           "groupedProperties": {
               "type": "object",
               "properties": {
                   "property1": {
                       "type": "string"
                   },
                   "property2": {
                       "type": "string"
                   }
               }
           }
       }
    }
    

    这是一次包含所有groupedProperties 的更简洁的方法。

    {
        "type": "object",
        "allOf": [
            { "$ref": "#/definitions/groupedProperties" }
        ],
        "definitions": {
            "groupedProperties": {
                "type": "object",
                "properties": {
                    "property1": {
                        "type": "string"
                    },
                    "property2": {
                        "type": "string"
                    }
                }
            }
        }
    }
    

    或者,由于您只是将它用于测试目的,您可以翻转它,以便定义引用架构。您可以在测试中使用该定义,而不会影响您的架构。

    {
        "type": "object",
        "properties": {
            "property1": { "type": "string" },
            "property2": { "type": "string" }
        },
        "definitions": {
            "groupedProperties": {
                "type": "object",
                "properties": {
                    "property1": { "$ref": "#/properties/property1" },
                    "property2": { "$ref": "#/properties/property2" }
                }
            }
        }
    }
    

    【讨论】:

    • 我对你的回答投了反对票,因为虽然它有专业的氛围,但我无法确认你所说的关于 JSON Refs 的任何信息。 JSONSchema 没有定义 JSON 引用,它只是使用它。 JSON Reference IETF draftJSON Schema Definition 都不包含诸如“$ref”之类的语句,它们应该只是属性,或者只能/不能只存在于特定位置。如果您有关于该主题的消息来源,请包括它们 - 我会改变我的投票。
    • 我对@9​​87654341@ 做了两个声明。第一个“$ref必须独立”记录在本节的最后一句中:tools.ietf.org/html/draft-pbryan-zyp-json-ref-03#section-3
    • 第二个“$ref 不应在属性中使用”是对最佳实践和实用性的陈述,而不是违反规范的陈述。将$ref 用于除其预期(尽管未记录)使用引用模式之外的任何内容都是非惯用的 JSON 模式,并且大多数验证器不支持它。事实上,我不知道有什么这样做的。尽管我同意验证器应该完全实现$ref,但我仍然不建议将它用于除了引用模式之外的任何其他用途。它从来没有必要,只会使模式更难阅读和维护。
    • 我希望这有助于解决您的问题。这个答案不值得投反对票。事实上,这是一个比公认的更好的答案。接受的答案没有错,但不完整。
    • 感谢您的澄清,即使我多次检查我错过了句子。我对您的回答的问题是在提出强有力的主张时缺乏参考材料,而不是答案本身的完整性。随意编辑答案以包含您在 cmets 中写的内容(必须对其进行编辑,以便我可以更改投票)。如果您没有时间,我会在几个小时内完成,然后更改我的投票。
    【解决方案2】:

    这与require 无关,对象键不是唯一的(因为您可以在一个对象中多次声明它们),但它们是可覆盖的(与声明两次的变量可覆盖相同)。您只会收到在两个具有相同名称的键上声明的最后一个值。

    我建议给 refs 一个可区分的 ID,这也有助于代码扩展时的清晰度

    【讨论】:

    • 我还没有找到任何说 $ref 可能有其他名称的东西,我认为它是一个关键字(没有深入研究它)。我从您的回答中猜想我可以在其中放置任意名称,例如在 shell 脚本中。我得试试看。我找到了另一种方法来获得我想要的东西。谢谢。
    • 我尝试为引用添加任意名称,这很有效。我想知道为什么没有人在网上的例子中使用任何不同的东西。此外,jsonlint 有效,但另一个无效。
    • 你是什么意思“为引用输入任意名称?”我尝试过$refOne: ./path/to/file and it does not work.
    猜你喜欢
    • 1970-01-01
    • 2020-01-25
    • 2016-05-25
    • 2013-07-09
    • 1970-01-01
    • 2016-10-10
    • 2021-12-11
    • 1970-01-01
    • 2019-03-27
    相关资源
    最近更新 更多