Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ ______________________________________________________________________
:hidden:

schema
reference_tables/dataset
reference_tables/resource
reference_tables/hazard
reference_tables/exposure
reference_tables/vulnerability
reference_tables/loss
browser
codelists
package_schema
Expand Down
105 changes: 105 additions & 0 deletions docs/reference/reference_tables/dataset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Dataset schema

```{contents} On this page
:local:
```
## Overview

```{mermaid}
---
config:
layout: elk
elk:
nodePlacementStrategy: SIMPLE
---

erDiagram

dataset {
string id
string(email) title
string risk_data_type
string(iri) license
}

publisher {
string name
string(email) email*
string(iri) url*
}

spatial {

}

contact_point {
string name
string(email) email*
string(iri) url*
}

creator {
string name
string(email) email*
string(iri) url*
}

dataset ||--|{ resource: includes
dataset ||--|| publisher: "published by"
dataset ||--|| spatial: "covers the area described by"
dataset ||--|| contact_point: "maintained by"
dataset ||--|| creator: "produced by"
```

## Properties

```{jsonschema} ../../../schema/rdls_schema_processed.json
:collapse: publisher,contact_point,creator,spatial,attributions,lineage/sources,referenced_by,resources,hazard,exposure,vulnerability,loss
:externallinks: >
: {
: "publisher":{"url":"#publisher-contact-point-and-creator","text":"Publisher, contact point, and creator"},
: "contact_point":{"url":"#publisher-contact-point-and-creator","text":"Publisher, contact point, and creator"},
: "creator":{"url":"#publisher-contact-point-and-creator","text":"Publisher, contact point, and creator"},
: "spatial":{"url":"#spatial-coverage","text":"Spatial coverage"},
: "attributions":{"url":"#attributions","text":"Attributions"},
: "lineage/sources":{"url":"#sources","text":"Sources"},
: "referenced_by":{"url":"#referenced-by","text":"Referenced by"},
: "resources":{"url":"../resource","text":"Resource"},
: "hazard":{"url":"#hazard-metadata","text":"Hazard metadata"},
: "exposure":{"url":"#exposure-metadata","text":"Exposure metadata"},
: "vulnerability":{"url":"#vulnerability-metadata","text":"Vulnerability metadata"},
: "loss":{"url":"#loss-metadata","text":"Loss metadata"}
: }
```

## Publisher, contact point and creator

```{jsonschema} ../../../schema/rdls_schema_processed.json
---
pointer: /properties/publisher
---
```

## Spatial coverage

```{jsonschema} ../../../schema/rdls_schema_processed.json
---
pointer: /properties/spatial
---
```

## Attributions

```{jsonschema} ../../../schema/rdls_schema_processed.json
---
pointer: /properties/attributions/items
---
```

## Sources

```{jsonschema} ../../../schema/rdls_schema_processed.json
---
pointer: /properties/lineage/properties/sources/items
---
```
1 change: 1 addition & 0 deletions docs/reference/reference_tables/exposure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Exposure metadata schema
47 changes: 47 additions & 0 deletions docs/reference/reference_tables/hazard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Hazard metadata schema

```{contents} On this page
:local:
```

## Properties

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/hazard
:collapse: event_sets
:externallinks: >
: {
: "event_sets":{"url":"#event-sets","text":"Event sets"}
: }
```

## Event sets

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/hazard/properties/event_sets/items
:collapse: hazards,spatial,events
:externallinks: >
: {
: "hazards":{"url":"#hazards","text":"Hazards"},
: "spatial":{"url":"#spatial-coverage","text":"Spatial coverage"},
: "events":{"url":"#events","text":"Events"}
: }
```

## Hazards

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/hazard/properties/event_sets/items/properties/hazards/items
```

## Spatial coverage

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/hazard/properties/event_sets/items/properties/spatial
```

## Events

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/hazard/properties/event_sets/items/properties/events/items
```
1 change: 1 addition & 0 deletions docs/reference/reference_tables/loss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Loss metadata schema
11 changes: 11 additions & 0 deletions docs/reference/reference_tables/resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Resource schema

```{contents} On this page
:local:
```

## Properties

```{jsonschema} ../../../schema/rdls_schema_processed.json
:pointer: /properties/resources/items
```
1 change: 1 addition & 0 deletions docs/reference/reference_tables/vulnerability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Vulnerability metadata schema
95 changes: 95 additions & 0 deletions process_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import json
from pathlib import Path
from referencing import Registry
from referencing.jsonschema import DRAFT202012

def deref_and_merge(obj, registry, path="root"):
if isinstance(obj, list):
return [deref_and_merge(item, registry, f"{path}[{i}]") for i, item in enumerate(obj)]
if not isinstance(obj, dict):
return obj

# 1. Standard 2020-12 $ref merging
if "$ref" in obj:
ref_uri = obj.pop("$ref")
resolved = registry.resolver().lookup(ref_uri).contents
obj = {**resolved, **obj}

# 2. Recursive call to process children first (so we merge from the bottom up)
obj = {k: deref_and_merge(v, registry, f"{path}.{k}") for k, v in obj.items()}

# 3. Handle allOf merging
if "allOf" in obj and isinstance(obj["allOf"], list):
new_all_of = []
if "properties" not in obj:
obj["properties"] = {}

for i, item in enumerate(obj["allOf"]):
current_item_path = f"{path}.allOf[{i}]"

# --- Validation 2: Strict Conditional Check ---
if "if" in item:
# Check for any keys that aren't 'if' or 'then'
extra_keys = set(item.keys()) - {"if", "then"}
if extra_keys:
raise ValueError(
f"Validation Error at {current_item_path}: "
f"Conditional 'if' found with unauthorized sibling keys: {extra_keys}. "
f"Only 'then' is allowed."
)
new_all_of.append(item)

# --- Validation 1: Property Collision Check ---
elif "properties" in item:
for prop_name in item["properties"]:
if prop_name in obj["properties"]:
raise ValueError(
f"Validation Error at {path}: "
f"Property collision detected for '{prop_name}'. "
f"Defined in both parent and allOf item."
)

# Merge structural properties
obj["properties"].update(item["properties"])

# Merge required arrays if they exist
if "required" in item:
current_req = obj.get("required", [])
obj["required"] = list(set(current_req) | set(item["required"]))

# Handle item that is just a schema but not a conditional or properties container
else:
# Check for collisions with top-level keys before merging
for k in item:
if k in obj and k != "properties": # properties handled above
raise ValueError(f"Collision at {path} for key: {k}")
obj.update(item)

# Final cleanup
if new_all_of:
obj["allOf"] = new_all_of
else:
del obj["allOf"]

return obj

# --- Execution ---
input_path = Path("schema/rdls_schema.json")
try:
schema = json.loads(input_path.read_text())
reg = Registry().with_resource(uri="", resource=DRAFT202012.create_resource(schema))

full_schema = deref_and_merge(schema, reg)

# Top-level cleanup
full_schema.pop("$defs", None)
full_schema.pop("definitions", None)

output_path = Path("schema/rdls_schema_processed.json")
output_path.write_text(json.dumps(full_schema, indent=4))
print(f"Successfully dereferenced and merged to {output_path}")

except ValueError as e:
print(f"FAILED: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
Loading
Loading