I'm trying to create a graph database for describing power systems and this is my first time using JSON-LD.
Steps so far:
Created a schema according to the following guide
Saved the schema to this url
Attempted to use JSON-LD playground to create and validate and instance of a power-station object described in the schema
The issue I'm facing is that my schema seems to be accepted (changing it creates an error) but no output is shown and no explanation is provided. Any help to work out what I'm missing would be much appreciated.
Schema
{
"$id": "https://osuked.github.io/Power-Station-Dictionary/power-station",
"type": "object",
"properties": {
"capacity": { "type": "float" },
"fuel-type": { "type": "string" }
},
"required": ["capacity", "fuel-type"]
}
Example object instance
{
"#context": "https://osuked.github.io/Power-Station-Dictionary/power-station.json",
"#id": "http://osuked.github.io/Drax",
"capacity": 12,
"fuel-type": "wind"
}
Check the definition of the context (https://json-ld.org/spec/latest/json-ld/#the-context). It must specify how your properties (capacity and fuel-type) map to RDF properties. You can either provide the definitions inline or point to a URL that contains this mapping (e.g. https://schema.org/docs/jsonldcontext.jsonld).
In your example, you provide the URL https://osuked.github.io/Power-Station-Dictionary/power-station.json. It contains a JSON document but does not contain the JSON-LD context, because JSON Schema != JSON LD (you might find this article helpful to understand the difference: https://dashjoin.medium.com/json-schema-schema-org-json-ld-whats-the-difference-e30d7315686a).
Therefore, the JSON LD playground does not show an error (no property definitions found) but also shows no parsed triples.
To fix this, you can try using "#context": "http://schema.org/", you can define a namespace prefix p,
{
"#context": {
"p": "https://osuked.github.io/Power-Station-Dictionary/power-station/"
},
"#id": "http://osuked.github.io/Drax",
"p:capacity": 12,
"p:fuel-type": "wind"
}
or define the properties individually:
{
"#context": {
"capacity": "https://osuked.github.io/Power-Station-Dictionary/power-station/capacity",
"fuel-type": "https://osuked.github.io/Power-Station-Dictionary/power-station/fuel-type"
},
"#id": "http://osuked.github.io/Drax",
"capacity": 12,
"fuel-type": "wind"
}
Related
I'm editing an OpenAPI JSON spec in IntelliJ. The automatic validation and code completion work very nicely.
The OpenAPI version used is 3.0.3, which IntelliJ detects correctly. It seems that it uses "openapi30.json" internally for validation, and all is good.
However, the file is getting very large and it's time to move some commonly-used models out of it using $ref.
This is where things break. The main spec looks like this (snippet):
{
"openapi": "3.0.3",
"info": {
"title": "Cars REST API",
"description": "Calls, Responses and DTOs for REST",
"version": "1.0.0"
},
"components": {
"schemas": {
"car": {
"$ref": "car.json"
},
"car-group": {
"$ref": "car-group.json"
}
And when editing it, IntelliJ recognizes it as "openapi30".
However, the referenced documents are not recognized. For example, the car.json file looks like this:
{
"car": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
}
}
And it's recognized simply as a JSON document, not an OpenAPI one, so there is no proper validation and no code completion, etc.
How does one tell IntelliJ that the file is part of an OpenAPI specification, to be validated as such? One should think this could be inferred from begin $ref'ed from the main spec, but this doesn't work.
Trying to add a $schema value in the referenced file had no effect (and probably isn't in line with the OpenAPI spec anyway).
Manually selecting the OpenAPI 3.0 file type for car.json is not helpful, because then validation (rightly) fails - as it doesn't have the top-level structure required (info, openapi, paths).
Perhaps some specific JSON schema mapping needs to be added in IntelliJ preferences? If that's the case, it would be actually a sub-schema or some tag in the main OpenAPI spec, how can that be done?
IntelliJ version is: IntelliJ IDEA 2021.3.2 (Ultimate Edition)
Any help would be greatly appreciated.
Ron!
Such functionality is not yet supported. Please vote for https://youtrack.jetbrains.com/issue/IDEA-284305
Consider an example in
https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/master/tests/draft6/ref.json#L414
the original schema is:
{
"allOf": [{
"$ref": "http://localhost:1234/bar#foo"
}],
"definitions": {
"A": {
"$id": "http://localhost:1234/bar#foo",
"type": "integer"
}
}
}
which is valid.
For this schema S, if I want to create a new schema by adding a combining schema outside this schema, like: {"not":S}, which is:
{
"not": {
"allOf": [{
"$ref": "http://localhost:1234/bar#foo"
}],
"definitions": {
"A": {
"$id": "http://localhost:1234/bar#foo",
"type": "integer"
}
}
}
}
with the Location-independent identifier with absolute URI, also use $id. But it is invalid.
The error message(using https://www.jsonschemavalidator.net/):
Error parsing schema
Message:
Error when resolving schema reference 'http://localhost:1234/bar#foo'. Path 'not.allOf[0]', line 3, position 20.
A similar example is:
{
"not": {
"allOf": [{
"$ref": "#foo"
}],
"definitions": {
"A": {
"$id": "#foo",
"type": "integer"
}
}
}
}
with the Location-independent identifier, is also invalid.
I cannot figure out why it is invalid after adding a parent schema if there are $ref and $id at the same time...
Here {"not":S} is just one possibility, also can consider {"anyOf":[{S}]}.
I know that $id declares a base URI against which $ref URI-references are resolved.
But what is the problem with the above schemas?
And how should I correct them?
I will so appreciate it if someone helps me out...
You are correct here, and your schema is correct. I would call this a bug in the implementation.
Your schema is valid for JSON Schema draft-07, but not JSON Schema draft 2019-09 or above. For 2019-09 and above, your $id value can't contain a non-empty fragment.
You can see the correct and valid behaviour on another web based validator, a web based version of the HyperJump validator: https://json-schema.hyperjump.io
This web based implementation defaults to latest (2020-12), but you can specify a draft version using $schema (for example "$schema": "http://json-schema.org/draft-07/schema#").
To see this working on HyperJump, either modify your schema to remove fragments in the identifier URIs, or specify that you're using draft-07.
What does mean this statement in json-ld context?
{
"#context": {
"#version": 1.1,
"id": "#id",
"type": "#type"
}
}
and
{
"#context": {
"id": {"#type": "#id", "#id": "#id"},
"type": {"#type": "#id", "#id": "#type"}
}
}
I do not figure out that expression means what.
Json-Ld is designed to be interoperable with rdf. Therefore it introduces certain keywords marked with #. This keywords are needed to create rdf-statements from the json document.
A good starting point to get familar with the underlying concepts is to play around with the Json-Ld Playground. You will find some examples there. You can use the examples to create conversions from one format into another.
Getting rid of the '#'-character
Sometimes the '#'-character can become unhandy, e.g. when working with Javascript. In such situations it is possible to define an alias for an '#'-keyword. Like shown in your context:
{
"#context": {
"id": "#id",
"type": "#type"
}
}
By defining aliases for '#'-keywords the actual json document is easier to consume by non-rdf applications while it is still possible to process the data as rdf.
I have a json schema which refers to another json schema present in another folder using "$ref" (relative path) and i get a "MalformedURLException".
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/Base",
"definitions": {
"Base": {
"type": "object",
"additionalProperties": false,
"properties": {
"event": {
"$ref": "com/artifacts/click/ClickSchema.json"
},
"arrival_timestamp": {
"type": "integer",
"minimum": 0.0
}
},
"title": "Base"
}
}
}
And the click schema in another folder is as follows:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "com/artifacts/click/ClickSchema.json",
"Event": {
"type": "object",
"additionalProperties": false,
"properties": {
"sourceName": {
"type": "string"
}
}
}
}
Can someone please help. I am using this schema validator.
A JSON Schema knows nothing about where it sits in a file, and nothing about the other fils in a folder, by default.
It looks like the library you're using recognises this, and suggests you use a special reference protocol (classpath) to target other files in a folder with ease:
https://github.com/everit-org/json-schema#loading-from-the-classpath
As your schemas grow you will want to split that up into multiple
source files and wire them with "$ref" references. If you want to
store the schemas on the classpath (instead of eg. serving them
through HTTP) then the recommended way is to use the classpath:
protocol to make the schemas reference each other.
This isn't something defined by JSON Schema.
The more common approach is to load in all the schemas you intend to use, and allow for local resolution where you have the files already. The library you're using also supports this: https://github.com/everit-org/json-schema#registering-schemas-by-uri
Sometimes it is useful to work with preloaded schemas, to which we
assign an arbitary URI (maybe an uuid) instead of loading the schema
through a URL. This can be done by assigning the schemas to a URI with
the #registerSchemaByURI() method of the schema loader. Example:
SchemaLoader schemaLoader = SchemaLoader.builder()
.registerSchemaByURI(new URI("urn:uuid:a773c7a2-1a13-4f6a-a70d-694befe0ce63"), aJSONObject)
.registerSchemaByURI(new URI("http://example.org"), otherJSONObject)
.schemaJson(jsonSchema)
.resolutionScope("classpath://my/schemas/directory/")
.build();
There are additional considerations if you intend for your schemas to be used by others. If that's the case, do comment, and I'll expand.
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?
http://example.com/root.json/document.json
http://example.com/t/document.json
http://example.com/t/test/document.json
Which of the $ids in #/tilda~0field must be considered as baseURI for the $ref in question and why.
$refs 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 $ids 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.
Start with http://example.com/root.json.
Change folders to t and use file inner.json.
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