简体   繁体   中英

How should a json-schema (draft7) implementation resolve `$ref`s defined in unknown keywords?

JSON-Schema-Test-Suite defines schemas such as this, and I assume they are valid:

{
    "tilda~field": {"type": "integer"},
    "slash/field": {"type": "integer"},
    "percent%field": {"type": "integer"},
    "properties": {
        "tilda": {"$ref": "#/tilda~0field"},
        "slash": {"$ref": "#/slash~1field"},
        "percent": {"$ref": "#/percent%25field"}
    }
}

Take this example below:

{
    "$id": "http://example.com/root.json",
    "definitions": {
        "A": { "type": "integer" }
    },
    "properties": {
        "$id": {
            "type": "string"
        },
        "attributes": {
            "$ref": "#/tilda~0field/slash~1field/$id"
        }
    },
    "tilda~field": {
        "$id": "t/inner.json",
        "slash/field": {
            "$id": {
                "$id": "test/b",
                "$ref": "document.json"
            }
        }
    }
}

Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?

Which of the $id s in #/tilda~0field must be considered as baseURI for the $ref in question and why.

$ref s are not resolved within unknown keywords because $ref and $id only apply inside schemas. Let's look at an example to see what I mean by this.

{
  "$id": "http://example.com/foo",
  "type": "object",
  "properties": {
    "aaa": {
      "const": { "$ref": "#/definitions/bbb" }
    },
    "bbb": { "$ref": "#/definitions/bbb" }
  },
  "ccc": { "$ref": "#/definitions/bbb" },
  "definitions": {
    "bbb": { "type": "string" }
  }
}
  • The document as a whole is a schema, so /$id is understood by JSON Schema.
  • The properties keyword is defined as an object whose values are schemas. Therefore, the value at /properties/bbb is a schema and /properties/bbb/$ref is understood by JSON Schema.
  • The value of the const keyword is unconstrained. The value at /properties/aaa/const may look like a schema, but it's just a plain JSON object. Therefore /properties/aaa/const/$ref is not understood by JSON Schema.
  • The value at /ccc is not a JSON Schema keyword, so it's value is not constrained and not a schema. Therefore, the $id and $ref keywords are not understood by JSON Schema.

That's how it works now. When you go back to older drafts (draft-05 iirc), it's a little different. Before then, $ref was defined in a separate specification called JSON Reference. JSON Schema extended JSON Reference. Therefore, the semantics of $ref applied everywhere it appeared in a JSON Schema.

EDIT:

What happens when a $ref inside a known keyword references a schema deep inside an unknown keyword. for example, what if #/properties/bbb referenced #/ccc ?

That's a really good question. Referencing #/ccc should be an error because #/ccc is not a schema and $ref only allows you to reference a schema.

I just saw your question on the JSON Schema site in an issue. I'll post here what I posted there as well. However, also look at the edit.


Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?

I think Section 8.2 gives the answer: "A subschema's "$id" is resolved against the base URI of its parent schema." This means that it will be http://example.com/t/test/document.json .

Which of the $id s in #/tilda~0field must be considered as baseURI for the $ref in question and why.

The base URI for this is the $id at the root, re-routed by the $id in tilda~field .

  1. Start with http://example.com/root.json .
  2. Change folders to t and use file inner.json .
  3. Change folders to test (inside t ) and use file document.json .

EDIT

Having a look at @customcommander's reply and realizing that the value in tilde~field isn't processed as a schema, I'd like to say that the #ref wouldn't be processed at all. It's just a plain JSON string with no inherent meaning.

Are you sure your second schema is valid though?

For example according to the JSON Schema Core specification , the $id property should be a string

If present, the value for this keyword MUST be a string

Therefore the following looks wrong to me:

"slash/field": {
  "$id": {
      "$id": "test/b",
      "$ref": "document.json"
  }
}

Then I think that your first $ref isn't correct either:

"attributes": {
  "$ref": "#/tilda~0field/slash~1field/$id"
}

It should probably read:

"attributes": {
  "$ref": "#/tilda~0field/slash~1field"
}

The same specification document also says this about $id and $ref : Cf this example

The "$id" keyword defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.

Or as Ajv simply puts it:

$ref is resolved as the uri-reference using schema $id as the base URI […].

Given the current state of your schema, I can only approximate the answer to your question but the ref would probably resolve to something like t/inner.json#document.json

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM