1

在我的 JSON 序列化数据中,我有嵌套对象:

{
  "A" : { "A1": 1,
          "A2": 2 },
  "B" : { "B1": 3,
          "B2": 4 }
}

由于给定的限制我无法影响,我需要展平结构。这意味着,深度大于 1 的每个对象都必须编码为字符串。应用在上面的例子中会是这样的:

{
  "A" : "\{\"A1\": 1, \"A2\": 2\}"
  "B" : "\{\"B1\": 3, \"B2\": 4\}"  
}

因为我需要在JSON Schema中表达这个约束,所以我几乎受其语法规则的约束。我猜这些对象的类型要么是string要么object

{
  "title": "My Schema",
  "type": "object",
  "properties": {

    "A": {
      "type": "string vs. object" 
    "B": {
      "type": "string vs. object"
}
4

2 回答 2

5

我同意,要么你选择object要么string类型。我查看了JSON Schema 文档,但找不到任何可以根据需要清楚地表达约束的内容。因此,我想到了对这两种方法的简短讨论。

类型字符串

JSON Schema 定义了七种原始类型,包括对象。字符串被简单地定义为 JSON 字符串。RFC 4627 定义如下 JSON 字符串

字符串是零个或多个 Unicode 字符的序列

这将适用于您的情况,即使必须限制字符串的内容。问题是如何传达限制。我会使用 adescription来引用另一个子模式。您甚至可以 pattern为字符串定义一个将子模式编码为正则表达式的方法。然而,这将非常容易出错并且根本不可读。但是,它可以用于更好地验证数据的模式。

{
  "title": "My Schema",
  "type": "object",
  "properties": {

    "A": {
      "type": "string".
      "description": "Please refer to http://... for the subschema."
    },
    "B": {
      "type": "string"
      "description": "Please refer to http://... for the subschema."
    }
}

这样做的好处是,很明显 JSON 提供程序必须将字符串放入该属性中。缺点是不能将完整的模式视为一次,描述可能会被监督,查找过程也很麻烦。string最后,当看到 type但object在子模式中定义了a时,它会非常混乱。

类型对象

通过简单地使用类型,您可以避免使用字符串的所有缺点。这里的问题实际上是,说明必须是字符串编码的描述将被忽略。

{
  "title": "My Schema",
  "type": "object",
  "properties": {

    "A": {
      "description": "Must be encoded as string",
      "type": "object",
      "properties": { "A1": { "type": "string" }, "A2": { "type": "string" } }
    },
    "B": {
      "description": "Must be encoded as string",
      "type": "object"
      "properties": { "A1": { "type": "string" }, "A2": { "type": "string" } }
    }
}

您总是可以完全伪造一些东西,例如使用类型string并为其定义properties,但这将是无效的 JSON Schema。


我建议您使用类型对象方法。虽然使用字符串类型存在这种约束,但总是会导致其背后的数据降级。可以通过其他方式强制执行约束。观察谁提供数据,将约束传达给各方,阻止与此约束相关的无效数据等。

谁知道呢,也许这个约束不会永远存在,如果这种情况发生变化,您将需要再次更改架构,在另一种情况下,您只需要删除说明字符串编码要求的注释。

于 2013-08-19T12:09:12.587 回答
1

我知道你已经选择了一个答案,但我想我只是在这里提到工作中的原则。

JSON Schema 试图避免进行“语义”验证——它们意味着验证标量类型中的数据(例如强制字符串格式或数值精度)。

如果您想像这样记录字符串值的内部格式,您可以使用一个"format"值(可能是自定义值,因为标准中没有合适的值)。

...或者你可以使用"media". 这个模式关键字的值是一个对象,它可以有一个属性"type",它指定字符串值的媒体类型。所以你的属性看起来像:

{
    "type": "string",
    "media": {
        "type": "application/json"
    }
}

验证器可以忽略"format",并且极不可能验证使用"media"(甚至没有直接提及),但就描述扁平化数据格式而言,"media"这是最准确的方法。

(但是,正如公认的答案所述,将其视为一种奇怪的序列化方法而不是数据约束在许多方面是一种更优雅的解决方案)。

于 2013-09-10T15:49:05.670 回答