Skip to content
Open
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
21 changes: 21 additions & 0 deletions .github/workflows/check-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Check Docs

on:
push:
pull_request:
workflow_dispatch:

jobs:
check-docs:
name: Check documentation
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: RDF syntax check
uses: AtomGraph/RDF-syntax-check@v1.0.5

- name: Check links
run: ./check-links.sh
40 changes: 40 additions & 0 deletions check-links.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -euo pipefail

REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
EXIT_CODE=0

resolve_url() {
python3 -c "
import urllib.parse, sys
base = 'http://x/' + sys.argv[1]
result = urllib.parse.urljoin(base, sys.argv[2])
print(result[len('http://x/'):])
" "$1" "$2"
}

while IFS= read -r -d '' ttl_file; do
rel="${ttl_file#"$REPO_DIR"/}"
url_path="${rel%.ttl}/"

while IFS= read -r url; do
[[ "$url" =~ ^https?:// ]] && continue
[[ "$url" =~ ^# ]] && continue
[[ "$url" =~ (^|/)uploads/ ]] && continue
[[ -z "$url" ]] && continue

path="${url%%#*}"
[[ -z "$path" ]] && continue
[[ "$path" =~ \.[a-zA-Z]+$ ]] && continue # skip links to files (e.g. .xsl)

resolved="$(resolve_url "$url_path" "$path")"
target_file="$REPO_DIR/${resolved%/}.ttl"

if [[ ! -f "$target_file" ]]; then
echo "BROKEN: $rel → $url (resolves to ${resolved%/}.ttl)"
EXIT_CODE=1
fi
done < <(grep -oE '(href|src|data)="[^"]*"' "$ttl_file" | sed 's/^[^"]*"//;s/"$//' || true)
done < <(find "$REPO_DIR" -name "*.ttl" -print0)

exit "$EXIT_CODE"
7 changes: 5 additions & 2 deletions demo/copenhagen/parking-facilities.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
# Main container document
<> a dh:Container ;
dct:title "Parking facilities" ;
rdf:_1 <#largest-parkings> ;
rdf:_1 <#largest-parkings-block> ;
rdf:_2 <#select-children> .

# Chart block
# Chart block (wrapped in ldh:Object per ContentMode contract)
<#largest-parkings-block> a ldh:Object ;
rdf:value <#largest-parkings> .

<#largest-parkings> a ldh:ResultSetChart ;
dct:title "Largest parking facilities" ;
spin:query <#parking-by-spaces-query> ;
Expand Down
5 changes: 4 additions & 1 deletion demo/copenhagen/root.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
dct:description "Geospatial and other open data about cities, imported by transforming CSV files to RDF" ;
rdf:_1 <#page-header> ;
rdf:_2 <#city-intro> ;
rdf:_3 <#facilities-overview> ;
rdf:_3 <#facilities-overview-block> ;
rdf:_4 <#main-library> ;
rdf:_5 <#charts> ;
rdf:_6 <#largest-parkings> ;
Expand All @@ -42,6 +42,9 @@
This dataset includes libraries, schools, parking facilities, sports centers, playgrounds, and more.</p>
</div>"""^^rdf:XMLLiteral .

<#facilities-overview-block> a ldh:Object ;
rdf:value <#facilities-overview> .

<#facilities-overview> a ldh:ResultSetChart ;
dct:title "Facilities by type" ;
spin:query <#facilities-by-type-query> ;
Expand Down
192 changes: 192 additions & 0 deletions demo/northwind-traders/admin/model/ns.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,34 @@ schema:PostalAddress a owl:Class ;
rdfs:label "Postal address" ;
rdfs:isDefinedBy : .

schema:ProductGroup a owl:Class ;
rdfs:label "Product group" ;
rdfs:isDefinedBy : .

schema:Corporation a owl:Class ;
rdfs:label "Corporation" ;
rdfs:isDefinedBy : .

schema:ContactPoint a owl:Class ;
rdfs:label "Contact point" ;
rdfs:isDefinedBy : .

schema:ParcelDelivery a owl:Class ;
rdfs:label "Parcel delivery" ;
rdfs:isDefinedBy : .

schema:OrderItem a owl:Class ;
rdfs:label "Order item" ;
rdfs:isDefinedBy : .

schema:Product a owl:Class ;
rdfs:label "Product" ;
rdfs:isDefinedBy : .

schema:Place a owl:Class ;
rdfs:label "Place" ;
rdfs:isDefinedBy : .

# properties

schema:broker a owl:ObjectProperty ;
Expand All @@ -47,6 +75,170 @@ schema:address a owl:ObjectProperty ;
rdfs:range schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:contactPoint a owl:ObjectProperty ;
rdfs:label "Contact point" ;
rdfs:domain schema:Corporation ;
rdfs:range schema:ContactPoint ;
rdfs:isDefinedBy : .

schema:employee a owl:ObjectProperty ;
rdfs:label "Employee" ;
rdfs:domain schema:Corporation ;
rdfs:range schema:Person ;
rdfs:isDefinedBy : .

schema:customer a owl:ObjectProperty ;
rdfs:label "Customer" ;
rdfs:domain schema:Order ;
rdfs:range schema:Corporation ;
rdfs:isDefinedBy : .

schema:orderDelivery a owl:ObjectProperty ;
rdfs:label "Order delivery" ;
rdfs:domain schema:Order ;
rdfs:range schema:ParcelDelivery ;
rdfs:isDefinedBy : .

schema:deliveryAddress a owl:ObjectProperty ;
rdfs:label "Delivery address" ;
rdfs:domain schema:ParcelDelivery ;
rdfs:range schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:provider a owl:ObjectProperty ;
rdfs:label "Provider" ;
rdfs:range schema:Corporation ;
rdfs:isDefinedBy : .

schema:category a owl:ObjectProperty ;
rdfs:label "Category" ;
rdfs:domain schema:Product ;
rdfs:range schema:ProductGroup ;
rdfs:isDefinedBy : .

schema:containedInPlace a owl:ObjectProperty ;
rdfs:label "Contained in place" ;
rdfs:domain schema:City ;
rdfs:range schema:Place ;
rdfs:isDefinedBy : .

schema:sponsor a owl:ObjectProperty ;
rdfs:label "Sponsor" ;
rdfs:domain schema:Person ;
rdfs:range schema:Person ;
rdfs:isDefinedBy : .

schema:orderedItem a owl:ObjectProperty ;
rdfs:label "Ordered item" ;
rdfs:isDefinedBy : .

schema:name a owl:DatatypeProperty ;
rdfs:label "Name" ;
rdfs:isDefinedBy : .

schema:identifier a owl:DatatypeProperty ;
rdfs:label "Identifier" ;
rdfs:isDefinedBy : .

schema:description a owl:DatatypeProperty ;
rdfs:label "Description" ;
rdfs:isDefinedBy : .

schema:legalName a owl:DatatypeProperty ;
rdfs:label "Legal name" ;
rdfs:domain schema:Corporation ;
rdfs:isDefinedBy : .

schema:telephone a owl:DatatypeProperty ;
rdfs:label "Telephone" ;
rdfs:isDefinedBy : .

schema:faxNumber a owl:DatatypeProperty ;
rdfs:label "Fax number" ;
rdfs:isDefinedBy : .

schema:jobTitle a owl:DatatypeProperty ;
rdfs:label "Job title" ;
rdfs:domain schema:Person ;
rdfs:isDefinedBy : .

schema:addressCountry a owl:DatatypeProperty ;
rdfs:label "Address country" ;
rdfs:domain schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:addressLocality a owl:DatatypeProperty ;
rdfs:label "Address locality" ;
rdfs:domain schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:postalCode a owl:DatatypeProperty ;
rdfs:label "Postal code" ;
rdfs:domain schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:streetAddress a owl:DatatypeProperty ;
rdfs:label "Street address" ;
rdfs:domain schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:addressRegion a owl:DatatypeProperty ;
rdfs:label "Address region" ;
rdfs:domain schema:PostalAddress ;
rdfs:isDefinedBy : .

schema:givenName a owl:DatatypeProperty ;
rdfs:label "Given name" ;
rdfs:domain schema:Person ;
rdfs:isDefinedBy : .

schema:familyName a owl:DatatypeProperty ;
rdfs:label "Family name" ;
rdfs:domain schema:Person ;
rdfs:isDefinedBy : .

schema:honorificPrefix a owl:DatatypeProperty ;
rdfs:label "Honorific prefix" ;
rdfs:domain schema:Person ;
rdfs:isDefinedBy : .

schema:birthDate a owl:DatatypeProperty ;
rdfs:label "Birth date" ;
rdfs:domain schema:Person ;
rdfs:isDefinedBy : .

schema:orderQuantity a owl:DatatypeProperty ;
rdfs:label "Order quantity" ;
rdfs:domain schema:OrderItem ;
rdfs:isDefinedBy : .

schema:discount a owl:DatatypeProperty ;
rdfs:label "Discount" ;
rdfs:domain schema:OrderItem ;
rdfs:isDefinedBy : .

schema:price a owl:DatatypeProperty ;
rdfs:label "Price" ;
rdfs:isDefinedBy : .

schema:orderDate a owl:DatatypeProperty ;
rdfs:label "Order date" ;
rdfs:domain schema:Order ;
rdfs:isDefinedBy : .

schema:expectedArrivalUntil a owl:DatatypeProperty ;
rdfs:label "Expected arrival until" ;
rdfs:domain schema:ParcelDelivery ;
rdfs:isDefinedBy : .

schema:url a owl:DatatypeProperty ;
rdfs:label "URL" ;
rdfs:isDefinedBy : .

schema:location a owl:ObjectProperty ;
rdfs:label "Location" ;
rdfs:isDefinedBy : .

# restrictions

[] a owl:Restriction ;
Expand Down
14 changes: 10 additions & 4 deletions demo/northwind-traders/categories.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<> a dh:Container ;
dct:title "Categories" ;
rdf:_1 <#category-intro> ;
rdf:_2 <#category-revenue> ;
rdf:_2 <#category-revenue-block> ;
rdf:_3 <#category-distribution> ;
rdf:_4 <#products-per-category> ;
rdf:_4 <#products-per-category-block> ;
rdf:_5 <#select-categories> .

# Intro XHTML
Expand All @@ -23,7 +23,10 @@
Analyzing category-level metrics helps identify portfolio strengths, diversification opportunities, and inventory priorities.</p>
</div>"""^^rdf:XMLLiteral .

# Category revenue chart
# Category revenue chart (wrapped in ldh:Object per ContentMode contract)
<#category-revenue-block> a ldh:Object ;
rdf:value <#category-revenue> .

<#category-revenue> a ldh:ResultSetChart ;
dct:title "Revenue by category" ;
spin:query <#category-revenue-query> ;
Expand Down Expand Up @@ -62,7 +65,10 @@ ORDER BY DESC(?revenue)""" .
Categories with more products may indicate core competencies or simply broader product lines.</p>
</div>"""^^rdf:XMLLiteral .

# Products per category chart
# Products per category chart (wrapped in ldh:Object per ContentMode contract)
<#products-per-category-block> a ldh:Object ;
rdf:value <#products-per-category> .

<#products-per-category> a ldh:ResultSetChart ;
dct:title "Products per category" ;
spin:query <#products-per-category-query> ;
Expand Down
14 changes: 10 additions & 4 deletions demo/northwind-traders/customers.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<> a dh:Container ;
dct:title "Customers" ;
rdf:_1 <#customers-intro> ;
rdf:_2 <#top-customers> ;
rdf:_2 <#top-customers-block> ;
rdf:_3 <#geographic-distribution> ;
rdf:_4 <#customers-by-country> ;
rdf:_4 <#customers-by-country-block> ;
rdf:_5 <#customer-insights> ;
rdf:_6 <#select-customers> .

Expand All @@ -24,7 +24,10 @@
and market concentration helps prioritize account management and target growth strategies.</p>
</div>"""^^rdf:XMLLiteral .

# Top customers chart
# Top customers chart (wrapped in ldh:Object per ContentMode contract)
<#top-customers-block> a ldh:Object ;
rdf:value <#top-customers> .

<#top-customers> a ldh:ResultSetChart ;
dct:title "Top 10 customers by revenue" ;
spin:query <#top-customers-query> ;
Expand Down Expand Up @@ -61,7 +64,10 @@ LIMIT 10""" .
Understanding geographic concentration helps guide expansion efforts and resource allocation.</p>
</div>"""^^rdf:XMLLiteral .

# Customers by country chart
# Customers by country chart (wrapped in ldh:Object per ContentMode contract)
<#customers-by-country-block> a ldh:Object ;
rdf:value <#customers-by-country> .

<#customers-by-country> a ldh:ResultSetChart ;
dct:title "Customers by country" ;
spin:query <#customers-by-country-query> ;
Expand Down
7 changes: 5 additions & 2 deletions demo/northwind-traders/employees.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<> a dh:Container ;
dct:title "Employees" ;
rdf:_1 <#employee-intro> ;
rdf:_2 <#sales-by-employee> ;
rdf:_2 <#sales-by-employee-block> ;
rdf:_3 <#select-employees> .

# Intro XHTML
Expand All @@ -21,7 +21,10 @@
contributions helps recognize top performers, identify coaching opportunities, and optimize territory assignments.</p>
</div>"""^^rdf:XMLLiteral .

# Sales by employee chart
# Sales by employee chart (wrapped in ldh:Object per ContentMode contract)
<#sales-by-employee-block> a ldh:Object ;
rdf:value <#sales-by-employee> .

<#sales-by-employee> a ldh:ResultSetChart ;
dct:title "Sales by employee" ;
spin:query <#sales-by-employee-query> ;
Expand Down
Loading
Loading