Skip to content

Commit 6f403d2

Browse files
committed
Add support for multiple schema/refs
1 parent daaf3da commit 6f403d2

4 files changed

Lines changed: 75 additions & 26 deletions

File tree

json_schema/base.schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"$schema" : "http://json-schema.org/draft-07/schema#"
3+
}

json_schema/geopackage_layers.py

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,70 @@
1+
import os
12
import gpt
3+
import jsonschema
24

3-
_component = __file__.split('.')[0]
4-
_schemafile = '.'.join([_component, 'schema', 'json'])
5+
_curdir = os.path.dirname(os.path.abspath(__file__))
56

6-
with open(_schemafile) as f:
7+
8+
def read_schemas(basedir, pattern='*.schema.json'):
9+
"""
10+
Return a dictionary with all schemas from 'basedir' matching 'pattern'
11+
"""
712
import json
8-
schema = json.load(f)
13+
from glob import glob
914

10-
def validate(gpkg_path):
11-
# import fiona
12-
# data = fiona.listlayers(gpkg_path)
13-
gpkg = gpt.read_file(gpkg_path)
15+
schemas = {}
16+
for fn in glob(os.path.join(basedir, pattern)):
17+
try:
18+
with open(fn) as f:
19+
js = json.load(f)
20+
except:
21+
print(f"Error loading JSON: '{fn}'")
22+
raise
23+
else:
24+
# If the schema has no "$id" key, we adhoc push one: the filename,
25+
# which is reasonable since this is the simplest, valid, and
26+
# normally the way schemas will cross-reference each other.
27+
_fn = os.path.basename(fn)
28+
if "$id" not in js:
29+
js["$id"] = _fn # +"#"
30+
schemas[js["$id"]] = js
31+
32+
return schemas
33+
34+
35+
schema_store = read_schemas(_curdir)
1436

15-
# print("\nGeoPackage layers/columns:")
16-
# for name,table in gpkg.layers:
17-
# print(name)
18-
# print(table.columns)
19-
# print()
2037

21-
# This is a workaround during devel, until I understand how to tell jsonschema about the DataFrames
22-
# data = {ln:{} for ln in gpkg.list()}
23-
# data['layer_styles']['geometry'] = list(gpkg['layer_styles']['geometry'].values)
24-
# data['layer_styles']['geometry'] = []
25-
# print(data)
26-
data = gpkg.to_json()
38+
def validate(gpkg_path, schema='geopackage_layers.schema.json'):
39+
# from jsonschema import Draft7Validator as Validator
40+
from jsonschema import RefResolver
41+
from jsonschema.validators import validator_for
2742

28-
import jsonschema
29-
res = jsonschema.validate(data, schema)
43+
# If we had a simple schmea we could use jsonschema's 'validate' function
44+
# (as we did as first):
45+
# > import jsonschema
46+
# > res = jsonschema.validate(data, schema)
47+
#
48+
# But since the schema tree got a bit more complex,
49+
# > https://json-schema.org/understanding-json-schema/structuring.html,
50+
# we now have to creack open the components a little bit.
51+
#
52+
# One of the steps taken was to create a very simple "base" schema.
53+
# The "base" schema has two purposes: (1) to be used as the base
54+
# schema for jsonschema's RefResolver object, and (2) to define the
55+
# version of json-schema (currently draft-07) we're using in one single place.
56+
57+
# Since we have "refs" in our schemas, we need a resolver to link them
58+
resolver = RefResolver.from_schema(schema_store['base.schema.json'], store=schema_store)
59+
60+
# Get the correct (or best) validator for our schema's version
61+
Validator = validator_for(schema_store['base.schema.json'])
62+
63+
# Put them all together to define the validator/schema set to use
64+
validator = Validator(schema_store[schema], resolver=resolver)
65+
66+
gpkg = gpt.read_file(gpkg_path)
67+
data = gpkg.to_dict()
3068

69+
res = validator.validate(data)
3170
return res

json_schema/geopackage_layers.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "http://json-schema.org/draft-07/schema#",
2+
"$ref": "base.schema.json",
33

44
"title": "Match Geopackage layers list",
55

@@ -10,19 +10,19 @@
1010

1111
"properties": {
1212

13-
"layer_styles" : { "type" : "object" },
13+
"layer_styles" : { "$ref" : "layer_layer_styles.json" },
1414
"geologic_units" : { "type" : "object" },
1515
"linear_features" : { "type" : "object" },
1616
"surface_features" : { "type" : "object" },
1717
"geologic_contacts" : { "type" : "object" }
1818
},
1919

2020
"required" : [
21-
"geologic_contacts",
22-
"geologic_units",
2321
"layer_styles",
22+
"geologic_units",
2423
"linear_features",
25-
"surface_features"
24+
"surface_features",
25+
"geologic_contacts"
2626
],
2727

2828
"patternProperties" : {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$id": "layer_layer_styles.json",
3+
"title": "QGIS 'layer_styles' schema",
4+
"description": "Defines the entries/rows of the table across the columns.",
5+
6+
"type": "object"
7+
}

0 commit comments

Comments
 (0)