diff --git a/.gitignore b/.gitignore
index f998a83..51328d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ linkeddatahub/.DS_Store
docs/docs.trix
docs/files.xml
docs/html
+docs/timestamps.xml
diff --git a/check-links.sh b/check-links.sh
index 9912349..48f04bf 100755
--- a/check-links.sh
+++ b/check-links.sh
@@ -15,7 +15,16 @@ print(result[len('http://x/'):])
while IFS= read -r -d '' ttl_file; do
rel="${ttl_file#"$REPO_DIR"/}"
- url_path="${rel%.ttl}/"
+
+ # A .ttl is served at Product categories represent different market segments with distinct characteristics and performance.
- Analyzing category-level metrics helps identify portfolio strengths, diversification opportunities, and inventory priorities. The segments the catalogue is organised into — beverages, condiments, produce and the rest.
+ Open one to see the products it holds. Each category is a market segment with its own performance. Revenue first, then the spread of
+ products behind it. Understanding how products are distributed across categories reveals portfolio balance and potential gaps.
- Categories with more products may indicate core competencies or simply broader product lines. Revenue and range don't always line up. A category can earn well on few lines, or spread wide
+ and earn little — the gap between the two charts is where the portfolio questions are. Understand customer value, geographic distribution, and purchasing patterns. Identifying top customers
- and market concentration helps prioritize account management and target growth strategies. Every company Northwind sells to, with its contact details and address. Open an account to see
+ its full order history. Our customer base spans multiple countries, with varying levels of market penetration.
- Understanding geographic concentration helps guide expansion efforts and resource allocation. The customer base spans many countries at very different depths. Where the accounts cluster is
+ where the account managers should be. Browse individual customer records below to view detailed order history, contact information,
- and relationship details. Each customer profile provides insights into purchasing behavior and account status. Not every account is worth the same. Revenue concentrates in a handful of them. Track employee sales performance and order processing metrics. Understanding individual
- contributions helps recognize top performers, identify coaching opportunities, and optimize territory assignments. Everyone on the Northwind payroll, who they report to and the territories they cover. Open a
+ record to see the orders they booked. Revenue booked per sales rep — the basis for recognising top performers and rebalancing
+ territory assignments. Every order links a customer, the sales rep who booked it, the shipper that delivered it and the
+ products it contains. Orders are listed newest first with their status — sort any column or
+ filter with the facets. Open one for its full master–detail view: line items with their
+ quantities and line totals, the catalogue price each was struck against, the delivery
+ and its address, and the people and companies involved. Track order volume, geographic distribution, and temporal trends. Understanding order patterns
- helps optimize inventory, predict demand, and identify growth opportunities across different markets. Beyond the individual records, how has order volume developed over time? Orders span multiple countries and regions. Analyzing geographic patterns reveals market penetration
- and helps identify expansion opportunities or regional challenges. Every order records three dates: the day it was placed, the day the customer needed it
+ by, and — once the parcel actually leaves the warehouse — the day it was dispatched.
+ Two questions fall out of those. How quickly does Northwind get an order out of the
+ door, and how often does it beat the date it promised? Orders still waiting to ship
+ are left out of the second chart, since they have no outcome yet. The table below shows sales performance broken down by region and year, enabling comparison
- of regional growth patterns and seasonal variations. Three carriers deliver every order, which makes them worth comparing on two
+ axes. How often does a carrier miss the date the customer was promised, and
+ how much revenue does each one move month to month? The first is a question
+ about reliability, the second about how the shipping mix has shifted. Analyze product performance, category distribution, and supplier relationships.
- The Northwind catalog includes products across multiple categories from various suppliers,
- each with unique pricing and inventory characteristics. Every product Northwind sells, with its category, supplier and unit price. Open one to see the
+ orders it appears in and the supplier behind it. Which lines actually carry the revenue? Category-level breakdowns live under
+ Categories. Understanding how products and revenue are distributed across categories helps identify
- market strengths and opportunities. The following charts break down revenue and product count by category. Northwind Traders works with suppliers worldwide to source products. The distribution of products
- across suppliers shows which partnerships are most productive and may indicate supply chain dependencies. Northwind sources from suppliers worldwide. How the catalogue spreads across them shows which
+ partnerships carry the range — and where the supply chain concentrates. The top level of the sales geography. Each region contains the
+ territories that reps are assigned to. The iconic sample database converted to an RDF Knowledge Graph Features include CSV data imports, SPARQL-based charts, faceted search and related results (parallax navigation) as well as
- rich documents composed of structured content backed by RDF Knowledge Graph data. This application was created on LinkedDataHub using the low code paradigm: no programming was required, only scripts that
- invoke LinkedDataHub's CLI commands. Explore key business metrics including sales trends, geographic distribution, and product performance. All visualizations are generated from live SPARQL queries over the RDF Knowledge Graph. Sales performance at a glance — how revenue is trending, what the discounting costs,
+ where the markets are and which products carry the mix. Revenue is what was billed, not what was listed. Every order line keeps the catalogue
+ price it started from alongside the price it actually went out at, so the gap between
+ them is what the sales rep gave away to win the deal. Measured against gross, that gap
+ swings between roughly 4% and 11% month to month — a commercial lever in its own
+ right, and one that never shows up in a revenue chart. Meet the top manager of Northwind Traders. The Vice President of Sales, with the territories, reports and order history attached to the role. Dive deeper into detailed analytics by exploring the containers below. Each section provides comprehensive insights into products, orders, customers, employees, and more. Open Orders for the order book and its master–detail line items, or go straight to products, customers, employees and the reference data behind them. The carriers that deliver Northwind's orders. Open one to see every delivery it handled. The companies Northwind buys from. Open a supplier to see everything it supplies to the
+ catalogue. The territories reps cover, plotted on the map and grouped into
+ regions. LinkedDataHub is a Knowledge Graph application platform by
AtomGraph that fully exploits the federated features of RDF and SPARQL.
It can also be used as an RDF-native content management platform. LinkedDataHub is an open source project that has its roots as a Linked Data publishing framework. However, since the 3.x release we have focused on Linked Data consumption, as we consider
+ LinkedDataHub is an open source project that has its roots as a Linked Data publishing framework. Over time we have focused on Linked Data consumption, as we consider
publishing a solved problem but continue to see a shortage of user-friendly consumption tools. A single LinkedDataHub instance hosts multiple dataspaces, each identified by its own (sub)domain and consisting of a pair of applications: the end-user application and its administration application on the LinkedDataHub is also a low code RDF Knowledge Graph application platform. It offers comprehensive development and management features: Checkout the user guide on application building. Follow the tutorial to build your first app, then see the user guide on application building for the extension layers. As an RDF-native CMS, LinkedDataHub provides a number of features for end-users: Architecturally LinkedDataHub is a read-write RDF Graph Store combined with a rich Linked Data/SPARQL client. LinkedDataHub does not persist RDF data itself but rather serves it from, and stores it in,
a backing triplestore, which by default is the Apache Jena Fuseki. Every document in LinkedDataHub's dataspace is also a named graph in the Graph Store and has both RDF and HTML representations. The client is implemented using XSLT 3.0, a standard, declarative data transformation language. The same stylesheets run in two environments: on the server (Saxon-HE) to produce the initial HTML response, and in the browser (Saxon-JS 3 with Interactive XSLT) to render the layout and drive all subsequent navigation without full page reloads. It can connect to any Linked Data resource or SPARQL 1.1 endpoint. Since version 3.x LinkedDataHub does not use the Linked Data Templates anymore. However they can still be used to publish Linked Data from SPARQL endpoints
+ LinkedDataHub no longer uses Linked Data Templates. However they can still be used to publish Linked Data from SPARQL endpoints
using Processor. You can find the changelog here. All the basics of LinkedDataHub. From installation to customizing the model and user interface. This guide will show how a LinkedDataHub application can be used to manage domain-specific RDF classes and instances. As an example, we will use SKOS concepts and concept schemes. Note that most management actions can also be performed using the CLI (Command Line Interface). Where applicable, the UI and CLI instructions are shown side by side. The UNESCO Thesaurus demo app demonstrates how SKOS vocabularies can be managed in LinkedDataHub. New to LinkedDataHub? The tutorial builds a complete application, from an empty dataspace to a published app. Setup is only required if you plan to run your own instance of LinkedDataHub. It consists of few steps, which involve creating a configuration file and running a
@@ -24,7 +25,7 @@
With LinkedDataHub, you obtain a WebID and use its client certificate for authentication. You can obtain the WebID either by setting up your own instance or signing up on
- an existing instance. Alternatively, you can authenticate using your social login. User interface changes are done by adding and overriding templates in XSLT stylesheets. Follow a tutorial to change the layout: create an XSLT stylesheet and override a template. The user guide covers the everyday tasks in more depth: editing content in place, managing dataspaces, installing packages, and working with version history. The reference describes every feature in full. You'll need a PEM version of the certificate for use with the command line interface scripts. During setup, it is stored under
- ssl/owner/cert.pem. If you got the certificate by email, you need to convert the PKCS12 file to PEM using OpenSSL. The command line interface reads the PKCS12 (.p12) file directly, so no conversion is needed. During setup it is stored under ssl/owner/keystore.p12.
+ curl wants a PEM version instead — it is stored under ssl/owner/cert.pem, and a certificate received by email can be converted from PKCS12 to PEM using OpenSSL. Unlike most LinkedDataHub resources, your WebID profile will have public access as required by the protocol. Your email address will be hidden however. Fortunately, LinkedDataHub makes it easy to notify the owner by issuing an access request. Navigate to the document you want to gain access to, click on the
Request access button and submit the form that appears, as shown below. You can choose the desired access modes.
-
+
Are you in? Then continue the get started guide or take a look at the UI overview.Category analysis
- Product categories
+ Where the money is
+ Product distribution
- Portfolio balance
+ Customer insights
- The account book
+ Geographic distribution
- Geographic distribution
+ Customer portfolio
- Account value
+ Employee performance
- The team
+ Sales performance
+ The order book
+ Order analytics
- Order analytics
+ Geographic distribution
- From order to doorstep
+ Regional performance
- Who carries the freight
+ Product analytics
- The catalogue
+ Product performance
+ Category performance
- Supplier relationships
- Supplier relationships
+ Sales regions
+ Northwind Traders
- Executive dashboard
- Executive dashboard
+ What the deals cost
+ Top manager
- Sales leadership
+ Explore more
- Browse the business
+ Getting it there
+ Where the goods come from
+ Sales territories
+ admin. subdomain.Low code application platform
Federated knowledge management and collaboration system
@@ -34,15 +38,16 @@
-
Setup
Get an account
Where to next
+
This section assumes you will be running on your local machine, i.e. localhost. If you intend to run it on a different host, change the system base URI.
+This section assumes you will be running on your local machine, i.e. localhost. If you intend to run it on a different host, change the system base URI.
+The administration application of each dataspace is served on the admin. subdomain — for the default setup that is https://admin.localhost:4443/. Browsers resolve *.localhost automatically and the generated server certificate covers the subdomain, so the local setup works out of the box. On any other host, make sure admin.<host> resolves in DNS and is covered by the server's TLS certificate (e.g. a wildcard certificate).
Prerequisites:
docker-compose up --build+
make up -- --build+ (make up forwards its arguments to docker-compose up; the -- is needed before arguments starting with -.) LinkedDataHub will start and mount the following sub-folders:
If you need to start fresh and wipe the existing setup, you can do that using:
-sudo rm -rf data datasets uploads ssl && docker-compose down -v+
make drop+
It stops the services, removes the Docker volumes, and wipes the local datasets, fuseki, ssl and uploads folders.
This will remove persisted RDF data, SSL keys, and uploaded files as well as the Docker volumes.
An agent is a person or a software agent that can be authorized to have certain modes of access to certain applications.
-A group is a named group of agents to which an authorization can @@ -127,6 +113,9 @@
Public access authorization allows access for non-authenticated agents.
+The owner's and secretary's authorizations are stored under stable URIs (acl/authorizations/owner-webid/ and acl/authorizations/secretary-webid/), so reloading the admin dataset does not create duplicates.
+If access is denied due to missing authorization, the agent can ask for it by issuing a request to the application's @@ -137,4 +126,36 @@
| Action | +CLI command | +
|---|---|
| Create group | +ldh admin acl create-group | +
| Create authorization | +ldh admin acl create-authorization | +
| Add agent to group | +ldh admin acl add-agent-to-group | +
| Make a document public | +ldh admin acl make-public | +
Ontologies are sets of domain concepts. The domain can span both documents (information resources) and abstract/physical things (non-information resources).
Ontologies can import other ontologies, both user-defined - and system ones provided by LinkedDataHub. The imports are retrieved during application initialization, and the application's namespace ontology - becomes a transitive union, i.e. is merged with its imports and imports of the imports etc.
+ and system ones provided by LinkedDataHub. The application's namespace ontology is resolved as a nativeowl:imports union graph —
+ the transitive closure of its imports — which is cached per ontology URI. No inference is materialized: the terms are served exactly as declared.
+ Package ontologies join the application's imports closure automatically. They are derived from the application's
+ ldh:import declarations at ontology load time and declared as owl:imports of the namespace ontology, so they resolve
+ like any other import.
owl:imports with uploaded filesDo not use owl:imports declarations that point to paths under uploads/. This can cause circular dependency deadlocks
@@ -110,6 +113,8 @@ WHERE {}
gets skolemized to a URI when submitted to the server.
Note that classes inherit constructors from superclasses in runtime. Subclasses do not have to redefine constructor properties already found in superclass constructors, only additional properties.
+Constructor instances are instantiated client-side: the constructors of the resource's types (including the superclass closure) are expanded
+ onto a single instance. For that to work, a constructor has to have an empty WHERE clause, as in the example above.
LinkedDataHub allows definition of new properties.
+LinkedDataHub allows definition of new properties. Like classes, properties are declared in the application's namespace ontology.
+ The expected values of a property on a class are described either with a SPIN property constraint (a mandatory-property check)
+ or with an OWL restriction (owl:allValuesFrom on the class), both of which the create/edit forms enforce.
The Import ontology action loads an external vocabulary and derives instance constructors for its classes.
+ Only the derived annotation ontology is persisted — the generated constructors plus an owl:imports of the canonical vocabulary
+ URI — and it is wired into the application's namespace ontology. The vocabulary itself resolves through its canonical URI as part of the imports closure.
| Action | +CLI command | +
|---|---|
| Create ontology | +ldh admin ontologies create-ontology | +
| Import external vocabulary | +ldh admin ontologies import-ontology | +
| Add ontology import | +ldh admin add-ontology-import | +
| Clear ontology from cache | +ldh admin clear-ontology | +
| Create class | +ldh admin ontologies add-class | +
| Add constructor | +ldh admin ontologies add-constructor | +
| Add property constraint | +ldh admin ontologies add-property-constraint | +
| Add restriction | +ldh admin ontologies add-restriction | +
Packages are reusable bundles of ontologies and stylesheets that provide vocabulary support with custom rendering for specific RDF vocabularies.
Version: Packages were introduced in LinkedDataHub 5.2.
+Version: Packages were introduced in LinkedDataHub 5.2. Since 5.10 an application installs one by declaring a single ldh:import triple in its settings, replacing the packages/install and packages/uninstall endpoints and the file system mutations they performed.
Note: Packages are declarative only (RDF + XSLT). They contain no Java code and integrate at installation-time, not runtime.
+Note: Packages are declarative only (RDF + XSLT). They contain no Java code, and they are composed into the application at request time rather than copied into it.
Available system modes include:
bs2:* — Bootstrap 2.3.2 components (PropertyList, Form, etc.)bs2:* — layout components (PropertyList, Form, etc.; the namespace is historically Bootstrap 2.3.2-based)xhtml:* — XHTML elements (Style, Script, etc.)Installation requires Control access to the administration application. See the step-by-step installation guide for detailed instructions.
-Installation will fail if these files do not exist.
-When you install a package, the system performs the following steps:
+An application imports a package with a single triple in its settings:
+<urn:linkeddatahub:apps/end-user> ldh:import <https://packages.linkeddatahub.com/skos/#this> .+
That declaration is the installation — nothing is copied into the dataspace or onto the file system. Packages are installed into the end-user application of a dataspace, and writing the triple requires write access to its settings document. See the step-by-step installation guide for the user interface and command line instructions.
+From the next request onwards, the server resolves the declaration:
ns.ttl) and PUTs it as a document to ${admin_base}ontologies/{hash}/ where {hash} is the SHA-1 hash of the ontology URI${admin_base}ontologies/namespace/)layout.xsl) and saves it to /static/{package-path}/layout.xsl where {package-path} is derived from the package URI (e.g., com/linkeddatahub/packages/skos/ for https://packages.linkeddatahub.com/skos/)/static/xsl/layout.xsl by adding import:
- <xsl:import href="../com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/layout.xsl"/> <!-- System --> -<xsl:import href="../com/linkeddatahub/packages/skos/layout.xsl"/> <!-- Package (added) -->-
ldt:ontology) to the application's ontology imports closure — it is declared as an owl:imports of the namespace ontology — so the package's classes, constructors, constraints and views become available on the ns endpoint and in the UI.ac:stylesheet) into the application stylesheet by appending an xsl:import after the existing imports, so package templates override the system ones.Important: After installing or uninstalling a package, you must restart the Docker service for XSLT stylesheet changes to take effect:
-docker-compose restart linkeddatahub-
Do not use --force-recreate as that would overwrite the stylesheet file changes.
Packages are applied in the order of their URIs. A package carrying only an ontology or only a stylesheet is applied in that respect alone, and one whose description cannot be resolved is skipped. If the composed stylesheet fails to compile — an unreachable package stylesheet URL, for instance — the application falls back to its own stylesheet.
Packages can be safely uninstalled, which removes:
-Removing the ldh:import triple uninstalls the package: from the next request onwards its ontology is out of the imports closure and its stylesheet is no longer composed in.
Note: Uninstalling a package does not remove user-created data that uses the package's vocabulary.
+Note: Uninstalling a package does not remove user-created data that uses the package's vocabulary. That data stays in the dataspace but may not display or function correctly without the package.
Packages use installation-time composition, NOT runtime composition:
+Packages are composed at request time out of the declaration, not integrated into the application ahead of it:
ldh:import triple per package and nothing elsePackage installation and uninstallation is performed via system endpoints on the admin application. See packages/install and packages/uninstall in the HTTP API reference.
After installing the SKOS package:
-webapp/ -├── static/ -│ ├── com/ -│ │ └── linkeddatahub/ -│ │ └── packages/ -│ │ └── skos/ -│ │ └── layout.xsl # Package stylesheet -│ └── xsl/ -│ ├── layout.xsl # End-user master stylesheet -│ └── admin/ -│ └── layout.xsl # Admin master stylesheet+
Packages installed with releases before 5.10 were webapp file mutations and do not carry over. Re-declare them with ldh:import.
Ensure the metadata contains ldt:ontology and ac:stylesheet properties pointing to the package resources.
Use the CLI to test your package installation:
-install-package.sh \\ - -b "https://localhost:4443/" \\ - -f ssl/owner/cert.pem \\ +Use the CLI to test your package installation — declaring the
+ldh:importtriple in the application's settings document is the installation:ldh patch \\ + -f ssl/owner/keystore.p12 \\ -p "$cert_password" \\ - --package "https://packages.linkeddatahub.com/schema.org/#this"+ "https://localhost:4443/settings" <<EOF +INSERT +{ + <urn:linkeddatahub:apps/end-user> <https://w3id.org/atomgraph/linkeddatahub#import> <https://packages.linkeddatahub.com/schema.org/#this> . +} +WHERE {} +EOF
CLI scripts can be used perform all actions available in the UI
-LinkedDataHub CLI wraps the HTTP API into a set of shell scripts with convenient parameters. The scripts should run on any Unix-based system. - They can be used for testing, automation, scheduled execution and such. It is usually much quicker to perform actions using CLI rather than the +
The ldh CLI can be used to perform all actions available in the UI
+LinkedDataHub CLI wraps the HTTP API into a single executable with convenient parameters. + It can be used for testing, automation, scheduled execution and such. It is usually much quicker to perform actions using the CLI rather than the user interface, as well as easier to reproduce.
-Some scripts correspond to a single request to LinkedDataHub, others combine others into tasks with multiple interdependent requests, such as the CSV import.
-You will need to supply a .pem file of your WebID certificate as well as its password as script arguments, among others.
-The CLI scripts live in the bin folder and need to be added to the $PATH environmental variable. For example:
export PATH="$(find bin -type d -exec realpath {} \\; | tr '\n' ':')$PATH"
- They also use the Jena's CLI commands internally, so make sure to have them on $PATH before running the scripts.
Some commands correspond to a single request to LinkedDataHub, others combine several into tasks with multiple interdependent requests, such as the CSV import.
+You will need a .p12 keystore of your WebID certificate as well as its password, among other arguments.
+The CLI lives in the cli folder of the LinkedDataHub repository. Building it requires Java 21 and Maven. The build produces a self-contained target/ldh.jar which the cli/bin/ldh launcher runs:
+cd cli +mvn package +export PATH="$PWD/bin:$PATH" +cd .. + +ldh --help+
If you will be using the CLI regularly, add the export line to your shell profile. Shell completion for bash and zsh is generated by the CLI itself:
source <(ldh generate-completion)+
The CLI talks to the HTTP API directly and embeds Apache Jena. Unlike the shell scripts it replaces, it needs no curl, python or Jena command line tools on $PATH.
Commands authenticate with a WebID client certificate read from a PKCS12 (.p12) keystore — the format produced by bin/webid-keygen.sh and shipped as ssl/owner/keystore.p12 for the owner agent:
+ldh get \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --accept text/turtle \\ + "https://localhost:4443/"+
Server certificates are not validated, so self-signed development instances work out of the box.
Common parameters used by most scripts include:
+Common parameters used by most commands include:
Other parameters are script-specific.
+Other parameters are command-specific. Most commands take the URI of the document they act on as a default (positional) parameter.
+The repeated parameters can be set once in the environment instead of being passed to every command:
+| Variable | +Parameter | +
|---|---|
| LDH_CERT_FILE | +-f, --cert-file |
+
| LDH_CERT_PASSWORD | +-p, --cert-password |
+
| LDH_BASE | +-b, --base |
+
| LDH_PROXY | +--proxy |
+
export LDH_CERT_FILE=./ssl/owner/keystore.p12 +export LDH_CERT_PASSWORD="$owner_cert_password" +export LDH_BASE=https://localhost:4443/ + +ldh create-container --parent "$LDH_BASE" --title "Concepts" --slug concepts+
Commands that create or append to a document print its URL as the only line on standard output, so they compose in shell pipelines. All diagnostics go to standard error.
+item=$(ldh create-item --container "$LDH_BASE" --title "Example" --slug example)+
Exit codes are 0 on success, 1 on an HTTP error status or runtime failure (the message goes to standard error, a stack trace with --verbose), and 2 on a usage error.
A usage message with parameters of a script is printed when the scripted is run without any arguments. There can be named parameters and default parameters, both of those can be optional. For example:
-$ add-select.sh -Creates a SPARQL SELECT query. - -Usage: add-select.sh options - -Options: - -f, --cert-pem-file CERT_FILE .pem file with the WebID certificate of the agent - -p, --cert-password CERT_PASSWORD Password of the WebID certificate - -b, --base BASE_URI Base URI of the application - --proxy PROXY_URL The host this request will be proxied through (optional) - - --title TITLE Title of the chart - --description DESCRIPTION Description of the chart (optional) - --uri URI URI of the query (optional) - - --query-file ABS_PATH Absolute path to the text file with the SPARQL query string - --service SERVICE_URI URI of the SPARQL service specific to this query (optional)-
The optional parameters are marked with (Optional). In this case there is no default argument, but some scripts require document (named graph) URI as the default parameter, e.g. ontology document URL.
-This is how an add-select.sh invocation would look like:
-add-select.sh \\ +A usage message with the parameters of a command is printed when the command is run without required arguments, or with
+--help. There can be named parameters and default parameters, both of those can be optional. For example:$ ldh add-select +Missing required options and parameters: '--title=TITLE', '--query-file=ABS_PATH', 'TARGET_URI' +Usage: ldh add-select [--verbose] [-b=BASE_URI] [--description=DESCRIPTION] + [-f=CERT_FILE] [-p=CERT_PASSWORD] [--proxy=PROXY_URL] + --query-file=ABS_PATH [--service=SERVICE_URI] + --title=TITLE [--uri=URI] TARGET_URI +Adds a SELECT query to a document. + TARGET_URI URI of the document + -b, --base=BASE_URI Base URI of the application (env: LDH_BASE) + --description=DESCRIPTION + Description of the query (optional) + -f, --cert-file=CERT_FILE .p12 (PKCS12) keystore with the WebID certificate + of the agent (env: LDH_CERT_FILE) + -p, --cert-password=CERT_PASSWORD + Password of the WebID certificate (env: + LDH_CERT_PASSWORD) + --proxy=PROXY_URL The host this request will be proxied through + (optional) (env: LDH_PROXY) + --query-file=ABS_PATH Path to the file with the query string + --service=SERVICE_URI URI of the SPARQL service (optional) + --title=TITLE Title of the query + --uri=URI URI of the query (optional, blank node if not set) + --verbose Print stack traces of errors+The optional parameters are marked with (optional). In this case the default parameter is the URI of the document the query is appended to.
+This is how an add-select invocation would look like:
+ldh add-select \\ -b "$base" \\ - -f ./ssl/owner/cert.pem \\ + -f ./ssl/owner/keystore.p12 \\ -p "$owner_cert_password" \\ --proxy "$proxy" \\ --title "Select concepts" \\ - --query-file "$pwd/queries/select-concepts.rq"+ --query-file "$pwd/queries/select-concepts.rq" \\ + "${base}queries/"
Currently supported:
+The subcommand groups admin, content and imports mirror the folder structure of the deprecated scripts. Currently supported:
| Purpose | -Script | +Command |
|---|---|---|
| GET request | -get.sh | +ldh get |
| POST request | -post.sh | +ldh post |
| PUT request | -put.sh | +ldh put |
| PATCH request | -patch.sh | +ldh patch |
| DELETE request | -delete.sh | +ldh delete |
| Create container document | -create-container.sh | +ldh create-container |
| Create item document | -create-item.sh | +ldh create-item |
| Append object block (instance of ldh:Object) to document | -content/add-object-block.sh | +ldh content add-object-block |
| Append XHTML block (instance of ldh:XHTML) to document | -content/add-xhtml-block.sh | +ldh content add-xhtml-block |
| Remove block from document | -content/remove-block.sh | +ldh content remove-block |
| Append service (instance of ldh:GenericService) to document | -add-generic-service.sh | +ldh add-generic-service |
| Append result set chart (instance of ldh:ResultSetChart) to document | -add-result-set-chart.sh | +ldh add-result-set-chart |
Append SELECT query (instance of sp:Select) to document |
- add-select.sh | +ldh add-select |
| Append SPARQL view (instance of ldh:View) to document | -add-view.sh | +ldh add-view |
| Create file | -add-file.sh | +ldh add-file |
| Create CONSTRUCT query | -add-construct.sh | +ldh add-construct |
| Create CSV import | -imports/add-csv-import.sh | +ldh imports add-csv-import |
| Import CSV data | -imports/import-csv.sh | +ldh imports import-csv |
| Create RDF import | -imports/add-rdf-import.sh | +ldh imports add-rdf-import |
| Import RDF data | -imports/import-rdf.sh | +ldh imports import-rdf |
Add owl:import to ontology |
- admin/add-ontology-import.sh | +ldh admin add-ontology-import |
| Clear and reload ontology | -admin/clear-ontology.sh | +ldh admin clear-ontology |
| Add agent to group | -admin/acl/add-agent-to-group.sh | +ldh admin acl add-agent-to-group |
| Create authorization | -admin/acl/create-authorization.sh | +ldh admin acl create-authorization |
| Create group | -admin/acl/create-group.sh | +ldh admin acl create-group |
| Make application publicly readable to any agent | -admin/acl/make-public.sh | +ldh admin acl make-public |
| Add class | -admin/ontologies/add-class.sh | +ldh admin ontologies add-class |
Add CONSTRUCT query |
- admin/ontologies/add-constructor.sh | +ldh admin ontologies add-constructor |
| Create ontology | -admin/ontologies/create-ontology.sh | +ldh admin ontologies create-ontology |
| Add property constraint | -admin/ontologies/add-property-constraint.sh | +ldh admin ontologies add-property-constraint |
| Add restriction | -admin/ontologies/add-restriction.sh | +ldh admin ontologies add-restriction |
Add SELECT query |
- admin/ontologies/add-select.sh | +ldh admin ontologies add-select |
| Import ontology | -admin/ontologies/import-ontology.sh | -|
| Packages | -||
| Install package | -admin/packages/install-package.sh | -|
| Uninstall package | -admin/packages/uninstall-package.sh | +ldh admin ontologies import-ontology |
Usage example:
-add-file.sh \\ - -b "https://localhost:4443/" \\ - -f ./ssl/owner/cert.pem \\ ++Usage example — a file is uploaded to the document that will hold it, so the document is created first:
+base="https://localhost:4443/" + +doc=$(ldh create-item \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --title "Friends" \\ + --container "$base") + +ldh add-file \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ -p "$owner_cert_password" \\ --title "Friends" \\ --file friends.csv \\ - --content-type text/csv+ --content-type text/csv \\ + "$doc"
add-file prints the content-addressed URI of the upload ({base}uploads/{sha1}) rather than the document URI.
See also the data import user guides.
+ldh get reaches a versioned document's Memento roles through mutually exclusive options: + --timemap (the version history), --version <sha> (the historical version at the given commit), and + --timegate with an optional --datetime (RFC 1123 or ISO 8601). --timegate prints the negotiated + version's URI as the only line on stdout, so it pipes into another ldh get:
+version=$(ldh get \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --timegate \\ + --datetime "2026-08-30T12:00:00Z" \\ + "$doc") + +ldh get \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --accept text/turtle \\ + "$version"+
Packages have no command of their own: an application imports a package with a single ldh:import triple, so ldh patch on the application's settings document is the whole interface. See the package management guide for the full install and uninstall commands.
The HTTP API shell scripts in the bin folder that ldh replaces are deprecated. The certificate and WebID tooling (webid-keygen.sh, webid-keygen-pem.sh, webid-uri.sh, webid-modulus.sh, server-cert-gen.sh) talks to no API and is not deprecated.
+Migrating from a script to its command means dropping the .sh suffix, prefixing the invocation with ldh (subfolders become subcommand groups, e.g. admin/acl/create-group.sh becomes ldh admin acl create-group), and passing the .p12 keystore to -f instead of the .pem certificate.
Find the CLI scripts on GitHub or check out the - demo apps that use them.
+Find the CLI on GitHub or check out the + demo apps that use it.
Content blocks and the basic data content actions.
Content list is a layout mode introduced in LinkedDataHub 3.x. It allow composition of rich, structured web documents from multiple types of content blocks.
+Content list is a layout mode that allows composition of rich, structured web documents from multiple types of content blocks.
The blocks are attached to the document resource using RDF sequence properties rdf:_1, rdf:_2 etc.
The index number in the property URI indicates the position of the content block on the document's content list.
The blocks have 2 main types: XHTML (ldh:XHTML) and object (ldh:Object).
The blocks can be re-arranged by dragging one of them and dropping them in a different position.
+The blocks have 2 types: XHTML (ldh:XHTML) and object (ldh:Object). These are the only types allowed as content block values — anything that is not XHTML markup, such as a query, a chart or an external resource, has to be wrapped into an ldh:Object. A built-in constraint rejects other values.
The blocks can be re-arranged by dragging one of them by its drag handle and dropping it in a different position. Every block also offers a button that copies the block's URI to the clipboard.
XHTML block is simply a fragment of XHTML, stored as a canonical XML literal (rdf:XMLLiteral) in the RDF document. It is edited in place using the rich-text editor, which also supports RDFa annotations.
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . + +<https://localhost:4443/concepts/example/#xhtml-block> + a ldh:XHTML ; + rdf:value "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">\\n<p>A paragraph</p>\\n</div>"^^rdf:XMLLiteral .+
Blocks other than XHTML content are called objects and have to have a URI that dereferences. Objects are embedded (transcluded) into the HTML page. You can use any RDF resource or uploaded file as an object.
+LinkedDataHub will first attempt to load RDF data from the object URI and render it as block. If that fails, it will simply embed it using the HTML <object> element. Object blocks can be used to embed queries, charts, and other LinkedDataHub system resources.
Built-in block types use a UI convention where their UI is split into left, main, and right content areas. The layout of the main content may depend on the active mode of the block. Left and right sections are block-type specific.
+@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix ac: <https://w3id.org/atomgraph/client#> . -<#select-children> a ldh:Object ; - rdf:value ldh:ChildrenView . +<https://localhost:4443/concepts/example/#object-block> + a ldh:Object ; + rdf:value <http://dbpedia.org/resource/Copenhagen> ; + ac:mode ac:MapMode .+
Content blocks can only be managed when the Content layout mode is active. The edit and delete buttons only appear for agents with write access.
+| Action | +Description | +
|---|---|
| Create XHTML block | +Click the XHTML button at the bottom of the page. Create the XHTML content in the rich-text editor. | +
| Create object block | +Click the Object button at the bottom of the page. Enter the object's value URI. Click Save. | +
| Update XHTML block | +Click into the block's content and edit it in place. The changes are saved automatically when the focus leaves the block — there is no separate save button. | +
| Update object block | +Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Change the object's value URI. Click Save. | +
| Delete | +Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Click the button to delete the block. | +
| Reorder | +Drag the block by its drag handle and drop it in a different position on the content list. | +
| Copy URI | +Click the copy button on the block to copy the block's URI to the clipboard. | +
| Action | +CLI command | +
|---|---|
| Create XHTML block | +ldh content add-xhtml-block | +
| Create object block | +ldh content add-object-block | +
| Delete | +ldh content remove-block | +
Blocks that embed/transclude any dereferenceable URI
-Blocks other than HTML content is called an object and has to have a URI that dereferences. Objects are embedded (transcluded) into the HTML page. You can use any RDF resource or uploaded file as an object.
-LinkedDataHub will first attempt to load RDF data from the object URI and render it as block. If that fails, it will simply embed it using the HTML <object> element. Object blocks can be used to embed queries, charts, and other LinkedDataHub system resources.
Built-in block types use a UI convention where their UI is split into left, main, and right content areas. The layout of the main content may depend on the active mode of the block. Left and right sections are block-type specific.
-@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . -@prefix ac: <https://w3id.org/atomgraph/client#> . - -<https://localhost:4443/concepts/example/#object-block> - a ldh:Object ; - rdf:value <http://dbpedia.org/resource/Copenhagen> ; - ac:mode ac:MapMode .-
| Action | -Description | -
|---|---|
| Create | -Click the Object button at the bottom of the page (in content mode). Enter the object's value URI. Click Save. | -
| Update | -Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Change the object's value URI. Click Save. | -
| Delete | -Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Click the button to delete the block. | -
| Action | -CLI script | -
|---|---|
| Create | -content/add-object-block.sh | -
| Update | -- |
| Delete | -- |
Blocks that embed XHTML markup as an RDF literal
-XHTML block is simply a fragment of XHTML, stored as a canonical XML literal (rdf:XMLLiteral) in the RDF document. It can be edited using a WYSIWYG editor.
@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . - -<https://localhost:4443/concepts/example/#xhtml-block> - a ldh:XHTML ; - rdf:value "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">\\n<p>A paragraph</p>\\n</div>"^^rdf:XMLLiteral .-
Content blocks can only be managed when the Content layout mode is active.
-| Action | -Description | -
|---|---|
| Create | -Click the XHTML button at the bottom of the page (in content mode). Create the XHTML content in the WYSIWYG editor. Click Save. | -
| Update | -Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Change the XHTML content in the WYSIWYG editor. Click Save. | -
| Delete | -Click the button in the top-right corner of the block (it will only appear when you move the mouse close to that corner). Click the button to delete the block. | -
| Action | -CLI script | -
|---|---|
| Create | -content/add-xhtml-block.sh | -
| Update | -- |
| Delete | -- |
dh:Container) and items (instances of dh:Item) are documents (instances of foaf:Document). Items cannot contain other documents.
The first level of resources in a container is referred to as its children (of which that container - is the parent, while all levels down the hierarchy are collectively referred to as + is the parent), while all levels down the hierarchy are collectively referred to as descendants.
When a user logs in, the application loads its root container (unless a specific URI was requested). From there, users can navigate down the resource hierarchy, starting with children of the root container. At - any moment there is only one current document per page, on which management actions can + any moment there is only one current document per page, on which management actions can be performed: it can be viewed, edited etc.
Containers are analogous to folders in a filesystem.
+Document properties such as sioc:has_parent, dct:created, dct:modified, acl:owner are automatically managed by LinkedDataHub.
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> . +@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix dct: <http://purl.org/dc/terms/> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix sioc: <http://rdfs.org/sioc/ns#> . +@prefix acl: <http://www.w3.org/ns/auth/acl#> . + +<https://localhost:4443/concepts/> + a dh:Container ; + rdf:_1 <https://localhost:4443/concepts/#select-children> ; + dct:created "2025-06-02T19:12:26.533Z"^^xsd:dateTime ; + dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ; + dct:title "Concepts" ; + sioc:has_parent <https://localhost:4443/concepts/> ; + acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> . + +<https://localhost:4443/concepts/#select-children> + a ldh:Object ; + rdf:value ldh:ChildrenView .+
Items are analogous to files in a filesystem.
+Document properties such as sioc:has_container, dct:created, dct:modified, acl:owner are automatically managed by LinkedDataHub.
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> . +@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . +@prefix ac: <https://w3id.org/atomgraph/client#> . +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix dct: <http://purl.org/dc/terms/> . +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix sioc: <http://rdfs.org/sioc/ns#> . +@prefix acl: <http://www.w3.org/ns/auth/acl#> . -<#select-children> a ldh:Object ; - rdf:value ldh:ChildrenView . +<https://localhost:4443/concepts/example/> + a dh:Item ; + rdf:_1 <https://localhost:4443/concepts/example/#xhtml-block> ; + rdf:_2 <https://localhost:4443/concepts/example/#object-block> ; + dct:created "2025-06-02T19:49:48.126Z"^^xsd:dateTime ; + dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ; + dct:title "Example" ; + sioc:has_container <https://localhost:4443/concepts/> ; + acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> . + +<https://localhost:4443/concepts/example/#xhtml-block> + a ldh:XHTML ; + rdf:value "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">\\n<p>A paragraph</p>\\n</div>"^^rdf:XMLLiteral . + +<https://localhost:4443/concepts/example/#object-block> + a ldh:Object ; + rdf:value <http://dbpedia.org/resource/Copenhagen> ; + ac:mode ac:MapMode .+
| Action | +Description | +
|---|---|
| Create | +Create a new child document by clicking the Create button. Fill out the form. Click Save. | +
| Update | +Open the current document editing form by clicking the Edit button in the action bar. Make changes. Click Save. | +
| Delete | +Delete the current document by clicking the Delete button in the action bar. | +
| Action | +CLI command | +
|---|---|
| Create container | +ldh create-container | +
| Create item | +ldh create-item | +
| Update | +ldh put | +
| Delete | +ldh delete | +
Containers are analogous to folders in a filesystem
-Document properties such as sioc:has_parent, dct:created, dct:modified, acl:owner are automatically managed by LinkedDataHub.
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> . -@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . -@prefix dct: <http://purl.org/dc/terms/> . -@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . -@prefix sioc: <http://rdfs.org/sioc/ns#> . -@prefix acl: <http://www.w3.org/ns/auth/acl#> . - -<https://localhost:4443/concepts/> - a dh:Container ; - rdf:_1 <https://localhost:4443/concepts/#select-children> ; - dct:created "2025-06-02T19:12:26.533Z"^^xsd:dateTime ; - dct:creator <https://localhost:4443/admin/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ; - dct:title "Concepts" ; - sioc:has_parent <https://localhost:4443/concepts/> ; - acl:owner <https://localhost:4443/admin/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> . - -<https://localhost:4443/concepts/#select-children> - a ldh:Object ; - rdf:value ldh:ChildrenView .-
| Action | -Description | -
|---|---|
| Create | -Create a new child document by clicking the Create button on the left of the navbar. Fill out the form. Click Save. | -
| Update | -Open the current document editing form by clicking the Edit button in the middle section of the navbar. Make changes. Click Save. | -
| Delete | -Delete the current document by clicking the Delete in the action bar (the right section of the navbar) | -
| Action | -CLI script | -
|---|---|
| Create | -create-container.sh | -
| Update | -put.sh | -
| Delete | -delete.sh | -
Items are analogous to files in a filesystem
-Document properties such as sioc:has_container, dct:created, dct:modified, acl:owner are automatically managed by LinkedDataHub.
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> . -@prefix ldh: <https://w3id.org/atomgraph/linkeddatahub#> . -@prefix ac: <https://w3id.org/atomgraph/client#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . -@prefix dct: <http://purl.org/dc/terms/> . -@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . -@prefix sioc: <http://rdfs.org/sioc/ns#> . -@prefix acl: <http://www.w3.org/ns/auth/acl#> . - -<https://localhost:4443/concepts/example/> - a dh:Item ; - rdf:_1 <https://localhost:4443/concepts/example/#xhtml-block> ; - rdf:_2 <https://localhost:4443/concepts/example/#object-block> ; - dct:created "2025-06-02T19:49:48.126Z"^^xsd:dateTime ; - dct:creator <https://localhost:4443/admin/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ; - dct:title "Example" ; - sioc:has_container <https://localhost:4443/concepts/> ; - acl:owner <https://localhost:4443/admin/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> . - -<https://localhost:4443/concepts/example/#xhtml-block> - a ldh:XHTML ; - rdf:value "<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">\\n<p>A paragraph</p>\\n</div>"^^rdf:XMLLiteral . - -<https://localhost:4443/concepts/example/#object-block> - a ldh:Object ; - rdf:value <http://dbpedia.org/resource/Copenhagen> ; - ac:mode ac:MapMode .-
| Action | -Description | -
|---|---|
| Create | -Create a new child document by clicking the Create button on the left of the navbar. Fill out the form. Click Save. | -
| Update | -Open the current document editing form by clicking the Edit button in the middle section of the navbar. Make changes. Click Save. | -
| Delete | -Delete the current document by clicking the Delete in the action bar (the right section of the navbar) | -
| Action | -CLI script | -
|---|---|
| Create | -create-item.sh | -
| Update | -put.sh | -
| Delete | -delete.sh | -
Built-in classes are defined in system ontologies while user-defined classes are defined in user ontologies.
TBD
+User-defined classes live in the application's namespace ontology, which is managed in the admin application. A class becomes creatable in the UI once it has a constructor: it then appears in the Create dropdown alongside the built-in classes, and its instances are created and edited using the same forms. See Change the model for a walkthrough of defining classes, constructors and constraints.
sp:AskASK queryASK querysp:ConstructCONSTRUCT queryCONSTRUCT queryldh:GraphChartCONSTRUCT/DESCRIBE query resultsCONSTRUCT/DESCRIBE query resultsldh:ResultSetChartSELECT query resultsSELECT query resultssp:SelectSELECT querySELECT queryldh:ViewSELECT query resultsSELECT query resultsResources that have customized UIs (such as queries, views, charts) are documented in more detail below.
+
+
+
Queries are SPARQL 1.1 query strings that can be executed interactively. They can be defined with a SPARQL + service that they execute against, otherwise they execute against the application's own SPARQL service.
+It is only possible to save valid SPARQL 1.1 query strings. SPARQL updates are currently not supported.
+
+
+
Charts can render both types of SPARQL results:
+SELECT results (ldh:ResultSetChart)DESCRIBE and CONSTRUCT (ldh:GraphChart)In that sense they are similar to the chart layout mode in + views, but charts also store the chart type as well as the category and series information: variable names in the + case of tabular results, and property URIs in the case of graph results.
+A chart references its query with spin:query and describes its rendering with the following properties:
| Property | +Applies to | +Description | +
|---|---|---|
ldh:chartType |
+ both | +One of ac:Table, ac:LineChart, ac:BarChart, ac:ScatterChart, ac:Timeline |
+
ldh:categoryVarName |
+ ldh:ResultSetChart |
+ Name of the SELECT variable that provides the category values |
+
ldh:seriesVarName |
+ ldh:ResultSetChart |
+ Name(s) of the SELECT variable(s) that provide the series values |
+
ldh:categoryProperty |
+ ldh:GraphChart |
+ URI of the property that provides the category values | +
ldh:seriesProperty |
+ ldh:GraphChart |
+ URI(s) of the property(ies) that provide the series values | +
The default chart type is the table. Other chart types might not apply to all result data; for example a + scatter chart will need numeric or datetime values for both category and series.
+
+
+
Views are interactive, paginated, and optionally ordered results of a SPARQL SELECT result set.
+ What is rendered in the UI is not directly the tabular result however, but descriptions of the resources selected
+ by the result set. That is achieved by on-the-fly SPARQL query rewriting: the SELECT is wrapped into
+ a DESCRIBE query; DESCRIBE reuses the same variables from the SELECT projection.
+ This will not work for all SELECT queries.
To render paginated lists of resources, legacy applications would normally have a dedicated API endpoint that + supports pagination, ordering etc. In LinkedDataHub, views achieve the same functionality by simply building the + SPARQL query string on the client-side. Therefore views can be seen as client-side "containers".
+Views can be rendered in multiple layout modes: properties, list, grid, table, map, chart, and graph. They also show + the total number of results and allow result ordering by property. In the table mode, columns can be sorted by clicking + their headers; the sort order follows each column's datatype.
+Because the SELECT is rewritten into a DESCRIBE over its projected variables, a view can only render terms that the triplestore is able to describe:
?label, a ?date, or any computed value) describes nothing, so the view renders empty.View results can be rendered using the same layout modes as the document layout modes.
+A view that carries ldh:container metadata renders a Create button that creates a new instance in that container, so a view can double as an entry point for the data it lists.
A view with ldh:showWhenEmpty set to false is hidden while its query returns no results.
On the left side, views provide faceted search which acts as a filter that narrows down the view results.
+By default the facets are generic and inferred from the triple patterns of the SPARQL SELECT query used by the view. They can be customized using XSLT.
Parallax navigation is a rather unique navigation approach that lends itself perfectly to graph data. It is enabled for container content and shown as Related results on the right side of the view. Parallax allows "jumping" from a result set to a related result set using the selected RDF property. It works in + combination with faceted search which can be used to filter the initial result set.
+For example, facets can be used to filter a set products that belong to a certain category, and then parallax can be used to jump to a set of companies that provide those products, and then further on to + a set representatives of those companies.
+
+
+
Resources can only be managed when the Properties layout mode is active.
+| Action | +Description | +
|---|---|
| Create | +Click the Create dropdown on the bottom of the page. Fill out the fields in the form that appears. Click Save. | +
| Update | +Click the button in the top-right corner of the resource header (in the middle column of the content). Make changes in the form that appears. Click Save. | +
| Delete | +Click the button in the top-right corner of the resource header. Click the button to delete the block. | +
The following resource types can be created using the command line interface. Any resource can be updated or deleted with ldh patch, which applies a SPARQL update to the resource's document.
+| Type | +Action | +CLI command | +
|---|---|---|
| CONSTRUCT | +Create | +ldh add-construct | +
| CSV import | +Create | +ldh imports add-csv-import | +
| File | +Create | +ldh add-file | +
| RDF import | +Create | +ldh imports add-rdf-import | +
| Result set chart | +Create | +ldh add-result-set-chart | +
| Select | +Create | +ldh add-select | +
| Service | +Create | +ldh add-generic-service | +
| View | +Create | +ldh add-view |
Resources that have customized UIs (such as queries, views, charts) are documented in more detail.
-Resources can only be managed when the Properties layout mode is active.
-| Action | -Description | -
|---|---|
| Create | -Click the Create dropdown on the bottom of the page. Fill out the fields in the form that appears. Click Save. | -
| Update | -Click the button in the top-right corner of the resource header (in the middle column of the content). Make changes in the form that appears. Click Save. | -
| Delete | -Click the button in the top-right corner of the resource header. Click the button to delete the block. | -
The following actions can also be performed using the command line interface.
-| Type | -Action | -CLI script | -
|---|---|---|
| ASK | -Create | -- |
| Application | -Create | -- |
| CONSTRUCT | -Create | -admin/ontologies/add-construct.sh | -
| CSV import | -Create | -imports/add-csv-import.sh | -
| File | -Create | -add-file.sh | -
| Graph chart | -Create | -- |
| RDF import | -Create | -imports/add-rdf-import.sh | -
| Result set chart | -Create | -add-result-set-chart.sh | -
| Select | -Create | -add-select.sh | -
| Service | -Create | -add-generic-service.sh | -
| View | -Create | -add-view.sh | -
Interactive charts based on SPARQL queries
-
-
-
Charts can render results both types of SPARQL results:
-SELECT resultsDESCRIBE and CONSTRUCTIn that sense they are similar to the chart layout mode in - views, but charts also store the chart type as well as the category and series information: variable names in the - case of tabular results, and property URIs in the case of graph results.
-The default chart type is the table. Other chart types might not apply to all result data; for example a - scatter chart will need a numeric or datetime values for both category and series.
-Interactive SPARQL queries
-
-
-
Queries are SPARQL 1.1 query strings that can be executed interactively. They can be defined with a SPARQL - service that they execute against, otherwise they execute against the application's own SPARQL service.
-It is only possible to save valid SPARQL 1.1 query strings. SPARQL updates are currently not supported.
-Paginated views based on SPARQL queries
-
-
-
Views are interactive, paginated, and optionally ordered results of a SPARQL SELECT result set.
- What is rendered in the UI is not directly the tabular result however, but descriptions of the resources selected
- by the result set. That is achieved by on-the-fly SPARQL query rewriting: the SELECT is wrapped into
- a DESCRIBE query; DESCRIBE reuses the same variables from the SELECT projection.
- This will not work for all SELECT queries.
To render paginated lists of resources, legacy applications would normally have a dedicated API endpoint that - supports pagination, ordering etc. In LinkedDataHub, views achieve the same functionality by simply building the - SPARQL query string on the client-side. Therefore views can be seen as client-side "containers".
-Views can be rendered in multiple layout modes: properties, list, grid, table, map, chart, and graph. They also show - the total number of results and allow result ordering by property.
-Because the SELECT is rewritten into a DESCRIBE over its projected variables, a view can only render terms that the triplestore is able to describe:
?label, a ?date, or any computed value) describes nothing, so the view renders empty.View results can be rendered using the same layout modes as the document layout modes.
-On the left side, views provide faceted search which acts as a filter that narrows down the view results.
-By default the facets are generic and inferred from the triple patterns of the SPARQL SELECT query used by the view. They can be customized using XSLT.
Parallax navigation is a rather unique navigation approach that lends itself perfectly to graph data. It is enabled for container content and shown as Related results on the right side of the view. Parallax allows "jumping" from a result set to a related result set using the selected RDF property. It works in - combination with faceted search which can be used to filter the initial result set.
-For example, facets can be used to filter a set products that belong to a certain category, and then parallax can be used to jump to a set of companies that provide those products, and then further on to - a set representatives of those companies.
-
-
-
The basic structure of resources in an application is analogous to the file system, but built using RDF - resources and relationships between them instead. There is a hierarchy of containers, - which are collections of items as well as sub-containers. Both containers - and items are documents. Items cannot contain other documents.
-The first level of resources in a container is referred to as its children (of which that container - is the parent), while all levels down the hierarchy are collectively referred to as - descendants.
-When a user logs in, the application loads its root container (unless a specific URI was requested). From there, - users can navigate down the resource hierarchy, starting with children of the root container. At - any moment there is only one current document per page, on which actions can - be performed: it can be viewed, edited etc.
+Each application's data is structured as a hierarchy of containers and items, analogous to folders and files in a file system. + See the document hierarchy reference for the details and the + management actions that can be performed on documents.
If you are ready to create a dataspace, see our step-by-step tutorial on dataspace management.
"""^^rdf:XMLLiteral . \ No newline at end of file diff --git a/docs/reference/http-api.ttl b/docs/reference/http-api.ttl index 550a004..8affe73 100644 --- a/docs/reference/http-api.ttl +++ b/docs/reference/http-api.ttl @@ -13,18 +13,18 @@ rdf:value """Learn how to read and write RDF data from/to LinkedDataHub applications over HTTP
LinkedDataHub implements a uniform, generic RESTful Linked Data API as defined by the - SPARQL 1.1 Graph Store Protocol. It adds a few conventions and constraints + SPARQL 1.1 Graph Store Protocol. It adds a few conventions (such as automatic document metadata) and constraints on top of it however.
LinkedDataHub UI supports 2 authentication methods:
See how those authentication methods can be configured or how to get an account on LinkedDataHub.
HTTP API access using CLI scripts or curl currently does not support the OIDC method.
+HTTP API access using the CLI or curl currently does not support the OIDC method.
Unlike earlier versions, LinkedDataHub 5.x manages the document hierarchy automatically.
-By default, LinkedDataHub treats an RDF document as an item by giving it the dh:Item type and attaching it to the parent container using sioc:has_container. If the client wants to create a container instead, it has to explicitly add the dh:Container type on the document resource; the new container will be attached to its parent using sioc:has_container. In either case, the URI of the new document's will be relative to its parent's.
By default, LinkedDataHub treats an RDF document as an item by giving it the dh:Item type and attaching it to the parent container using sioc:has_container. If the client wants to create a container instead, it has to explicitly add the dh:Container type on the document resource; the new container will be attached to its parent using sioc:has_parent. In either case, the URI of the new document will be relative to its parent's.
LinkedDataHub will also manage additional document metadata, such as its owner and creation/modification timestamps.
For example, this HTTP request to create a new container (Turtle syntax):
-PUT /namedgraph/new-container/ HTTP/1.1
-Host: linkeddatahub.com
+ PUT /new-container/ HTTP/1.1
+Host: localhost:4443
Content-Type: text/turtle
@prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
@@ -154,30 +154,30 @@ Content-Type: text/turtle
@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix acl: <http://www.w3.org/ns/auth/acl#> .
-<https://linkeddatahub.com/namedgraph/new-container/>
+<https://localhost:4443/new-container/>
a dh:Container ;
dct:created "2025-03-31T21:46:21.984Z"^^xsd:dateTime ;
- dct:creator <https://linkeddatahub.com/namedgraph/admin/acl/agents/fda0009e-191b-4f07-838c-5daf2a74b35f/#this> ;
+ dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ;
dct:title "New container" ;
- sioc:has_parent <https://linkeddatahub.com/namedgraph/> ;
- acl:owner <https://linkeddatahub.com/namedgraph/admin/acl/agents/fda0009e-191b-4f07-838c-5daf2a74b35f/#this> .
+ sioc:has_parent <https://localhost:4443/> ;
+ acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> .
The HTTP request to produce a new item can be empty:
-PUT /namedgraph/new-container/ HTTP/1.1
-Host: linkeddatahub.com
+ PUT /new-item/ HTTP/1.1
+Host: localhost:4443
Content-Type: text/turtle
It will create an item document with the following triples:
- @prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
+ @prefix dh: <https://www.w3.org/ns/ldt/document-hierarchy#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix acl: <http://www.w3.org/ns/auth/acl#> .
-<https://linkeddatahub.com/namedgraph/new-item/>
+<https://localhost:4443/new-item/>
a dh:Item ;
dct:created "2025-03-31T20:45:42.802Z"^^xsd:dateTime ;
- dct:creator <https://linkeddatahub.com/acl/agents/d47e1f9b-c8d0-4546-840f-5d9fbb479da2/#id9d3814f2-53bc-42e9-b1ab-46cbc9a94263> ;
- sioc:has_container <https://linkeddatahub.com/namedgraph/> ;
- acl:owner <https://linkeddatahub.com/admin/acl/agents/d47e1f9b-c8d0-4546-840f-5d9fbb479da2/#id9d3814f2-53bc-42e9-b1ab-46cbc9a94263> .
+ dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ;
+ sioc:has_container <https://localhost:4443/> ;
+ acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> .
The built-in constraints are similar to, but separate from the ontology constraints.
In dataspaces with versioning enabled, document URLs answer additional query parameters that expose the version + history through the standard Memento (RFC 7089) protocol:
+?version=<commit-sha>Memento-Datetime and immutable caching. Snapshots are read-only: write methods answer 405 Method Not Allowed?timemapapplication/link-format as RFC 7089 requires?timegateAccept-Datetime header answers 302 Found with the closest version in LocationSee the versioning reference for details.
+Every LinkedDataHub application provides a SPARQL endpoint on sparql path (relative to the application's base URI). It supports the
@@ -207,6 +221,8 @@ Content-Type: text/turtle
PATCH with a SPARQL update edits it — this is how packages are installed and uninstalled. Editing is restricted to end-user applications: a PATCH on an admin application's settings answers 422 Unprocessable Entity<script type="application/ld+json">) and parses it as RDF using JSON-LD 1.1, so pages annotated with schema.org markup
can be browsed as Linked Data. The schema.org JSON-LD context is bundled with LinkedDataHub and served locally, so no external network request is made to resolve it.
The proxy only accepts external (non-relative to the current application's base URI) URLs; local URLs have to be dereferenced directly.
+The proxy forwards the origin's ETag and Last-Modified validators and passes conditional request headers
+ (If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since) through, so preconditioned
+ writes against proxied documents are evaluated at the origin. Error statuses from the origin reach the client unchanged.
The Linked Data proxy makes dataspaces interoperable across origins: one dataspace's client can browse, query, and write to another + origin's dataspace, whether on the same LinkedDataHub instance or a different one.
+Link headers the proxy forwards, so views and charts over
+ remote documents query the remote endpointPATCH) or appends (POST) sent through the proxy under the origin's
+ If-Match preconditionIn the user interface this means you can browse a remote dataspace and + add data to its documents the same way as to local ones, provided the remote access control allows it.
GET and HEAD RDF responses from the backend triplestores (not LinkedDataHub responses) are cached automatically by LinkedDataHub using Varnish
as HTTP proxy cache. You can check the age of the response by inspecting the Age response header (the value is in seconds).
LinkedDataHub sends ETag response headers that are derived as hashes of the requested document's RDF content. Every serialization format (HTML, RDF/XML, Turtle etc.) gets a distinct ETag value.
LinkedDataHub sends ETag response headers that are derived as hashes of the requested document's RDF content. Every serialization format (HTML, RDF/XML, Turtle etc.) gets a distinct ETag value, and language-negotiated HTML representations factor the accepted languages into the tag.
HTML responses carry a Content-Language negotiated against the languages the UI ships, and advertise Vary: Accept-Language so shared caches keep the renderings apart.
Caching of LinkedDataHub responses can be enabled on the nginx HTTP proxy server by uncommenting the add_header Cache-Control directives in the platform/nginx.conf.template file.
- Caching of /uploads/ and /static/ namespaces is enabled by default (since version 4.0.4).
Types of data imports supported by LinkedDataHub
+Both import types use a user-defined SPARQL CONSTRUCT query to map the incoming data to the final RDF representation and to connect it to the documents in LinkedDataHub's dataset. These are the rules that hold for mapping queries:
BASE value is automatically set to the imported file's URI. Do not add an explicit BASE to the query.$base binding is set to the value of the application's baseURIOPTIONAL for optional values (such as optional cell values in CSV)BIND() to introduce new values and/or cast literals to the appropriate result datatype or URIencode_for_uriGRAPH block in the constructor template to construct triples for a specific documentdct:title values are mandatory for documents.foaf:primaryTopic propertyWe are planning to provide a UI-based mapping tool in the future.
+This step provides a semantic "lift" for the generic RDF output of the previous step by mapping it to classes and properties from specific vocabularies. It also connects instances in the imported data to the documents in LinkedDataHub's dataset.
-These are the rules that hold for mapping queries:
-BASE value is automatically set to the imported file's URI. Do not add an explicit BASE to the query.$base binding is set to the value of the application's baseURIOPTIONAL for optional cell valuesBIND() to introduce new values and/or cast literals to the appropriate result datatype or URIencode_for_uriGRAPH block in the constructor template to construct triples for a specific documentdct:title values are mandatory for documents.foaf:primaryTopic propertyWe are planning to provide a UI-based mapping tool in the future.
+The mapping is a user-defined SPARQL CONSTRUCT that follows the shared mapping query rules.
In this example we produce a SKOS concept paired with its item (document) for each country:
diff --git a/docs/reference/imports/rdf.ttl b/docs/reference/imports/rdf.ttl index 68cd42e..1cd44cc 100644 --- a/docs/reference/imports/rdf.ttl +++ b/docs/reference/imports/rdf.ttl @@ -62,18 +62,7 @@This step is used to transform the RDF data that is being imported, if necessary (to a different vocabulary, for example). It also connects instances in the imported data to the documents in LinkedDataHub's dataset.
-The mapping is a user-defined SPARQL CONSTRUCT. These are the rules that hold for mapping queries:
BASE value is automatically set to the imported file's URI. Do not add an explicit BASE to the query.$base binding is set to the value of the application's baseURIOPTIONAL for optional valuesBIND() to introduce new values and/or cast literals to the appropriate result datatype or URIencode_for_uriGRAPH block in the constructor template to construct triples for a specific documentdct:title values are mandatory for documents.foaf:primaryTopic propertyWe plan to provide a UI-based mapping tool in the future.
+The mapping is a user-defined SPARQL CONSTRUCT that follows the shared mapping query rules.
In this example we pair each SKOS concept from the imported dataset with a new document:
diff --git a/docs/reference/stylesheets.ttl b/docs/reference/stylesheets.ttl index 9f30f32..6b4ec0c 100644 --- a/docs/reference/stylesheets.ttl +++ b/docs/reference/stylesheets.ttl @@ -85,19 +85,19 @@ixsl:http://saxonica.com/ns/interactiveXSLTbs2:http://graphity.org/xsl/bootstrap/2.3.2xhtml:http://www.w3.org/2011/http#http://www.w3.org/1999/xhtmlldt:lapp:https://w3id.org/atomgraph/linkeddatahub/apps#document() XSLT function. To avoid XSLT errors on any possible error responses, it is advisable
to do a conditional check using the doc-available() function before doing the actual document() call.
For example, instead of hardcoding the title of this document as Stylesheets, we can use the following code to load it and output it on the fly:
-<xsl:value-of select="key('resources', 'https://docs.linkeddatahub.com/reference/stylesheet/', document('https://docs.linkeddatahub.com/reference/stylesheet/'))"/>
+ <xsl:value-of select="key('resources', 'https://docs.linkeddatahub.com/reference/stylesheets/', document('https://docs.linkeddatahub.com/reference/stylesheets/'))"/>
In case this document changes its title, all such references would automatically render the updated title. On the other hand, it incurs the overhead of making an HTTP request.
LinkedDataHub's default stylesheets are using this feature extensively. In fact, one HTML page is rendered from a dozen of RDF/XML documents.
Built-in ontologies as well as some other system and well-known ontologies, have a local copy in
diff --git a/docs/reference/user-interface.ttl b/docs/reference/user-interface.ttl
index d99a1c5..1db28c7 100644
--- a/docs/reference/user-interface.ttl
+++ b/docs/reference/user-interface.ttl
@@ -28,7 +28,7 @@
The application title or logo in the top-left always links to the root container of the current application.
-The address bar in the middle accepts the URI of a resource to navigate to. Entering an external http:// or https:// URL loads it through the Linked Data proxy so that it can be browsed within LinkedDataHub.
The address bar in the middle accepts the URI of a resource to navigate to. Entering an external http:// or https:// URL loads it through the Linked Data proxy so that it can be browsed within LinkedDataHub.
On the right, dropdown menus provide access to the list of applications and to your user account.
Due to current web browser limitations, it is not possible to logout using client certificate authentication.
@@ -46,8 +46,9 @@
The path leading from the current document up the parent/child hierarchy to the root container is shown in
the breadcrumb bar, where the current document is always the last breadcrumb. The user can always
open any of the ascendant containers by clicking breadcrumbs left from the current one. The icon shows the
- type of the current document (container or item). A label is displayed when the URL currently being browsed is external.
Further to the right, the action bar displays buttons for performing actions on the current document.
+In dataspaces with versioning enabled, the action bar also shows the document's last-modified timestamp. Clicking it opens the version history dialog, which lists the document's versions with the agents that authored them.
Last but not least, the settings button provides a link to the administration application.
LinkedDataHub navigates within a single page. When you follow a link to an external document (for example a resource fetched through the - Linked Data proxy), it opens in its own tab so that several documents can be kept open side by side. + Linked Data proxy), it opens in its own tab so that several documents can be kept open side by side. A sticky tab bar appears at the top of the page once the first external tab is opened.
Each tab keeps its own content pane, and modal dialogs (such as creation and edit forms) are scoped to the active tab pane. Switching between tabs is cached, so returning to a previously opened tab does not re-fetch it. Closing a tab removes its pane and falls back to the base document's tab.
@@ -124,4 +125,9 @@The language of the user interface is negotiated from the browser's language preferences (the Accept-Language header) against the languages the UI translation bundle ships. There is no in-app language switcher — the browser setting is the single source of the language preference. If none of the preferred languages are available, the UI falls back to English.
Data is language-aware as well: property values are ordered by the reader's language preference rather than filtered by it, so values in other languages remain visible, each displaying its own language tag.
+Git-backed document versioning with Memento access to the history
+A dataspace can be configured to mirror every document write into a GitHub repository. Each document is stored as a sorted + N-Triples file and every write becomes a commit authored with the writing agent's WebID, so the repository holds a complete, + attributable history of the dataspace's documents.
+The history is accessible over HTTP through the standard Memento (RFC 7089) + protocol — historical versions, a TimeMap, and datetime negotiation through a TimeGate — as well as through the + version history dialog in the user interface and the + command line interface.
+Versioning is enabled per dataspace:
+lapp:versioningRepository:
+ <urn:linkeddatahub:apps/end-user>
+{
+ <urn:linkeddatahub:apps/end-user> a lapp:EndUserApplication ;
+ ldt:service <urn:linkeddatahub:services/end-user> ;
+ lapp:versioningRepository <urn:linkeddatahub:versioning/end-user> .
+}
+
+<urn:linkeddatahub:versioning/end-user>
+{
+ <urn:linkeddatahub:versioning/end-user> a doap:GitRepository ;
+ doap:location <https://github.com/OWNER/REPO> ;
+ github:branch "main" ;
+ github:pathPrefix "graphs" .
+}
+ <urn:linkeddatahub:versioning/end-user>
+{
+ <urn:linkeddatahub:versioning/end-user> a:authToken "github_pat_..." .
+}
+ From then on, every successful document write in the dataspace is committed to the repository. Writes from different documents + share one commit chain per branch, and a conflicting commit is retried rather than dropped, so concurrent writers do not lose versions.
+GET with the ?version=<commit-sha> query parameter serves the document as it was at that commit. The
+ response carries a Memento-Datetime header with the commit datetime, the commit SHA as the ETag, and immutable
+ Cache-Control — a historical version never changes.
Snapshots are read-only: only acl:Read is advertised in the Link headers and write methods answer
+ 405 Method Not Allowed. In the user interface a snapshot page shows a notice banner with a link back to the current version.
GET with the ?timemap query parameter serves the document's version history. In RDF formats the TimeMap is described
+ with PROV-O: a prov:Collection of prov:Entity mementos, each
+ prov:specializationOf the document, prov:generatedAtTime its commit datetime, and prov:wasRevisionOf its
+ predecessor. Requesting application/link-format serves the serialization RFC 7089 requires.
A TimeMap of a document with no versions answers 404 Not Found, and ordinary documents answer 406 Not Acceptable
+ for application/link-format.
The Memento hypermedia uses the IANA-registered relation types: the document advertises its timemap and timegate in
+ Link headers, a historical version links back to the document with rel=original, and the TimeMap identifies itself with
+ rel=self.
GET with the ?timegate query parameter performs datetime negotiation: the version closest to the
+ Accept-Datetime request header is answered with 302 Found and its URI in Location, with ties resolved
+ towards the more recent version. Without Accept-Datetime, the most recent version is selected. The response carries
+ Vary: accept-datetime.
From the version history dialog, a document can be restored to an earlier version — the + restore rolls forward as a new commit, so the versions rolled past stay in the TimeMap — and any two versions can be compared as a diff + rendered on the document page.
+ldh get reaches a versioned document's Memento roles through mutually exclusive options:
+| Option | +Description | +
|---|---|
| --timemap | +The version history (PROV-O in RDF formats, or application/link-format via --accept) |
+
| --version <sha> | +The historical version at the given commit | +
| --timegate | +Datetime negotiation; the optional --datetime takes an RFC 1123 or ISO 8601 datetime. Prints the negotiated version's URI as the only line on stdout, so it pipes into another ldh get | +
Use LinkedDataHub's built-in Linked Data browser to explore remote datasources
-LinkedDataHub's has a built-in Linked Data browser which is accessed through the navigation bar. Enter a http:// or https:// URL and
- press Enter or click the search button.
The browser supports all standard RDF formats as well as JSON-LD embedded in HTML page's <script> elements, which is often used to publish schema.org metadata.
When the data loads successfully, you can navigate it the same way as your local documents, switch between different layout modes etc. You can also add the data into your dataspace.
-If an RDF document cannot be read from the supplied URL, an error message will be shown.
-Browse, navigate and search local and remote data
++ +
+LinkedDataHub has a built-in Linked Data browser which is accessed through the navigation bar. Enter a http:// or https:// URL and
+ press Enter or click the search button.
The browser supports all standard RDF formats as well as JSON-LD embedded in HTML page's <script> elements, which is often used to publish schema.org metadata.
When the data loads successfully, you can navigate it the same way as your local documents, switch between different layout modes etc. You can also add the data into your dataspace.
+If an RDF document cannot be read from the supplied URL, an error message will be shown.
+Document tree is a widget that enables quick overview of the application's document hierarchy. Each document is shown as a node in the tree; container documents + can be expanded to reveal the children documents.
+The widget can be accessed by sliding the mouse to the left edge of the screen (on responsive layouts, it is always visible).
+
+
+
In addition to navigating by document hierarchy, LinkedDataHub lets you navigate by class. The Classes list in the left sidebar shows the classes (rdf:type values) that occur in your data, each labelled with the number of its instances and ordered with the most-used classes first.
Class-based navigation is most useful when:
+The classes list is derived from the data itself, so it reflects whatever types are present — no ontology needs to be defined. It respects your access control settings — you'll only see classes and instances you're authorized to access.
+Backlinks are shown in the right-side navigation for every resource in property layout mode. + They display a list of resources which have properties with the current resource as the object.
+You can lookup resources by typing a phrase (it does not have to be complete, start with a few letters) into the search box at the top of the left sidebar.
+A dropdown list will appear if there are any matches. Use up/down keys or mouse click to select one of the results, and you will be redirected to its document.
+The matching is done by looking for substrings using SPARQL regex() in common literal properties such as dct:title, rdfs:label, foaf:name etc. You can find the exact query in Queries / Select labelled.
The same widget is used for autocomplete inputs in the create/edit forms.
+
+
+
You can use SPARQL to query data from the application's SPARQL service.
+Using LinkedDataHub as a low-code platform for Knowledge Graph applications
Every component in LinkedDataHub is data-driven and was designed with extensibility in mind. You can override behavior (e.g. Java method or XSLT template) without having to modify LinkedDataHub's codebase, and more importantly, without having to write the same logic from scratch.
+If you are building your first app, start with the tutorial — this guide covers the layers beyond it.
The following sections are split by component/layer and explain how to extend them when building bespoke apps.
You can go a long way just by mounting files (e.g. config files, ontologies, stylesheets) into LinkedDataHub's default Docker setup. But you may also want to build a dedicated Docker image for your app using LinkedDataHub as the base. Usually this is done to COPY files inside the image or RUN additional commands.
The recommended approach is a multi-stage Docker build: the first stage uses Maven to compile your WAR overlay, and the second stage copies it into the LinkedDataHub base image alongside any static files:
-FROM maven:3.8.4-openjdk-17 AS maven
+ FROM maven:3.9-eclipse-temurin-21 AS maven
WORKDIR /usr/src/myapp
@@ -29,7 +30,7 @@ RUN mvn clean install
# =================
-FROM atomgraph/linkeddatahub:5.3.2
+FROM atomgraph/linkeddatahub:5.10.0
WORKDIR $CATALINA_HOME
@@ -50,13 +51,13 @@ COPY files/style.css /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/cs
<dependency>
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub</artifactId>
- <version>5.5.3</version>
+ <version>5.10.0</version>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>com.atomgraph</groupId>
<artifactId>linkeddatahub</artifactId>
- <version>5.5.3</version>
+ <version>5.10.0</version>
<type>war</type>
</dependency>
</dependencies>
@@ -108,7 +109,7 @@ COPY files/style.css /usr/local/tomcat/webapps/ROOT/static/com/example/myapp/cs
RDF
You can modify or extend the default RDF datasets used by LinkedDataHub. However, a better practice is to use the
- CLI scripts to create documents and to import CSV and RDF data.
+ CLI to create documents and to import CSV and RDF data.
First, either upload the XSLT file or mount it using Docker and docker-compose.override.yml:
-version: "2.3" -services: ++-First, either upload the XSLT file or mount it using Docker and docker-compose.override.yml:
+services: linkeddatahub: volumes: - ../LinkedDataHub-Apps/demo/skos/files/skos.xsl:/usr/local/tomcat/webapps/ROOT/static/com/atomgraph/linkeddatahub/demo/skos/xsl/index.xsl:ro-Then change the value of
-ac:stylesheeton the dataspace with base URIhttps://localhost:4443/to the relative URI of the stylesheet:<urn:linkeddatahub:apps/end-user> a lapp:EndUserApplication ; +Then change the value of
+ac:stylesheeton the dataspace with base URIhttps://localhost:4443/to the URL of the stylesheet. The value has to be an absolute URL on the application's own origin:<urn:linkeddatahub:apps/end-user> a lapp:EndUserApplication ; ... - ac:stylesheet <static/com/atomgraph/linkeddatahub/demo/skos/xsl/index.xsl> ; + ac:stylesheet <https://localhost:4443/static/com/atomgraph/linkeddatahub/demo/skos/xsl/index.xsl> ; ...-
pwd=$(realpath -s $PWD)
+base="https://localhost:4443/"
+admin_base="https://admin.localhost:4443/"
-create-construct.sh \\
- -b "${base}admin/" \\
- -f ./ssl/owner/cert.pem \\
+ldh admin ontologies add-constructor \\
+ -b "$admin_base" \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
--uri "${base}ns#ConstructConcept" \\
--label "Construct concept" \\
- --slug construct-concept \\
--query-file "${pwd}/queries/construct-concept.rq" \\
- "${base}admin/model/ontologies/namespace/"
+ "${admin_base}ontologies/namespace/"
+ The model lives in the administration application, whose origin is the dataspace origin with an admin. prefix — so -b and the target document URL both use $admin_base, while the ontology terms being defined keep the end-user origin.
create-property-constraint.sh \\
- -b "$base" \\
- -f ./ssl/owner/cert.pem \\
+ ldh admin ontologies add-property-constraint \\
+ -b "$admin_base" \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
- --uri "https://localhost:4443/ns#MissingPrefLabel" \\
+ --uri "${base}ns#MissingPrefLabel" \\
--label "Missing skos:prefLabel" \\
- --slug missing-pref-label \\
--property "http://www.w3.org/2004/02/skos/core#prefLabel" \\
- "${base}admin/model/ontologies/namespace/"
+ "${admin_base}ontologies/namespace/"
create-class.sh \\
- -b "$base" \\
- -f ./ssl/owner/cert.pem \\
+ ldh admin ontologies add-class \\
+ -b "$admin_base" \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
--uri "http://www.w3.org/2004/02/skos/core#Concept" \\
--label "Concept" \\
- --slug concept \\
- --constructor "{$base}ns#ConstructConcept" \\
- --constraint "{$base}ns#MissingPrefLabel" \\
- "${base}admin/model/ontologies/namespace/"
+ --constructor "${base}ns#ConstructConcept" \\
+ --constraint "${base}ns#MissingPrefLabel" \\
+ "${admin_base}ontologies/namespace/"
After this, a new XHTML block should be appended to the page, replacing the form.
To edit an XHTML block, follow these steps:
-To edit an XHTML block, click anywhere inside it and make changes in place. The changes are saved automatically when the focus leaves the block — there is no separate save button.
To remove an XHTML block, follow these steps:
To add a new XHTML block with the value <p>A paragraph</p>, replace owner_cert_password with the value of the corresponding secret and execute the following command:
-content/add-xhtml-block.sh \\ - -b "https://localhost:4443/" \\ - -f ./ssl/owner/cert.pem \\ +ldh content add-xhtml-block \\ + -f ./ssl/owner/keystore.p12 \\ -p "$owner_cert_password" \\ - --fragment "xhtml-block" \\ - --value "<div xmlns=\\\\\\"http://www.w3.org/1999/xhtml\\\\\\"><p>A paragraph</p></div>" \\ + --uri "#xhtml-block" \\ + --value '<div xmlns="http://www.w3.org/1999/xhtml"><p>A paragraph</p></div>' \\ "https://localhost:4443/concepts/example/"+
--uriis resolved against the document URI, so #xhtml-block identifies the block within it. Leave it out to let the block be a blank node.
To add a new object block with the value http://dbpedia.org/resource/Copenhagen, replace $owner_cert_password with the value of the corresponding secret and execute the following command:
-content/add-object-block.sh \\
- -b "https://localhost:4443/" \\
- -f ./ssl/owner/cert.pem \\
+ ldh content add-object-block \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
- --fragment "object-block" \\
+ --uri "#object-block" \\
--value "http://dbpedia.org/resource/Copenhagen" \\
"https://localhost:4443/concepts/example/"
Read more about content blocks.
"""^^rdf:XMLLiteral . \ No newline at end of file diff --git a/docs/user-guide/create-data/create-documents.ttl b/docs/user-guide/create-data/create-documents.ttl index 897aad1..58d900e 100644 --- a/docs/user-guide/create-data/create-documents.ttl +++ b/docs/user-guide/create-data/create-documents.ttl @@ -44,9 +44,9 @@Replace owner_cert_password with the value of the corresponding secret and execute the following command:
-create-container.sh \\
+ ldh create-container \\
-b "https://localhost:4443/" \\
- -f ./ssl/owner/cert.pem \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
--title "Concepts" \\
--slug "concepts" \\
diff --git a/docs/user-guide/edit-content.ttl b/docs/user-guide/edit-content.ttl
index 2ebb68f..5cecbce 100644
--- a/docs/user-guide/edit-content.ttl
+++ b/docs/user-guide/edit-content.ttl
@@ -14,7 +14,7 @@
XHTML content blocks in LinkedDataHub are living documents: authenticated users with write access can click directly into the content to edit it, apply rich-text formatting, and annotate any span of text with RDFa — linking words and phrases to terms in the Knowledge Graph without leaving the page.
Entering edit mode
- Click anywhere inside an XHTML block to enter edit mode. The block gains a focus outline and the editor toolbar appears above the action bar. Clicking outside the block (including the surrounding column margins) returns the block to read mode.
+ Click anywhere inside an XHTML block to enter edit mode. The block gains a focus outline and the editor toolbar appears above the action bar. Clicking outside the block (including the surrounding column margins) returns the block to read mode.
Edit mode is only available to authenticated users who have write access to the document. The block remains read-only for all other visitors.
diff --git a/docs/user-guide/import-data/import-csv-data.ttl b/docs/user-guide/import-data/import-csv-data.ttl
index 95e1c9a..9d95490 100644
--- a/docs/user-guide/import-data/import-csv-data.ttl
+++ b/docs/user-guide/import-data/import-csv-data.ttl
@@ -89,14 +89,25 @@
- Checkout the Command line interface (CLI) scripts into a folder on your machine. Provide a list of arguments to the import-csv script and execute it. For example:
- import-csv.sh \\
- -b "https://localhost:4443/" \\
- -f ./ssl/owner/cert.pem \\
+ Build the command line interface (CLI) and put it on your $PATH. The import is described by a document, which the command takes as its last argument, so create that document first. For example:
+ base="https://localhost:4443/"
+
+doc=$(ldh create-item \\
+ -b "$base" \\
+ -f ./ssl/owner/keystore.p12 \\
+ -p "$owner_cert_password" \\
+ --title "Places" \\
+ --container "$base")
+
+ldh imports import-csv \\
+ -b "$base" \\
+ -f ./ssl/owner/keystore.p12 \\
-p "$owner_cert_password" \\
--title "Places" \\
--query-file places.rq \\
- --csv-file places.csv
+ --csv-file places.csv \\
+ "$doc"
+ --delimiter defaults to , and can be set to another character.
Checkout the Command line interface (CLI) scripts into a folder on your machine. Provide a list of arguments to the import-rdf script and execute it. For example:
-import-rdf.sh \\ - -b "https://localhost:4443/" \\ - -f ./ssl/owner/cert.pem \\ +Build the command line interface (CLI) and put it on your
+$PATH. The import is described by a document, which the command takes as its last argument, so create that document first. For example:base="https://localhost:4443/" + +doc=$(ldh create-item \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --title "Concepts" \\ + --container "$base") + +ldh imports import-rdf \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ -p "$owner_cert_password" \\ --title "Concepts" \\ --rdf-file concepts.ttl \\ --content-type "text/turtle" \\ - --graph "${base}skos/"+ --graph "${base}skos/" \\ + "$doc"
Checkout the Command line interface (CLI) scripts into a folder on your machine. Provide a list of arguments to the import-rdf script and execute it. For example:
-import-rdf.sh \\ - -b "https://localhost:4443/" \\ - -f ./ssl/owner/cert.pem \\ +Build the command line interface (CLI) and put it on your
+$PATH. The import is described by a document, which the command takes as its last argument, so create that document first. For example:base="https://localhost:4443/" + +doc=$(ldh create-item \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --title "Concepts" \\ + --container "$base") + +ldh imports import-rdf \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ -p "$owner_cert_password" \\ --title "Concepts" \\ --rdf-file concepts.ttl \\ --content-type "text/turtle" \\ - --query-file concepts.rq+ --query-file concepts.rq \\ + "$doc"
See the configuration reference for more details about these files.
Application base URIs need to be relative to the system base URI configured in the .env file. A change of system base URI currently requires a change of application base URIs, otherwise they will not be reachable.
+Application base URIs need to be relative to the system base URI configured in the .env file. A change of system base URI currently requires a change of application base URIs, otherwise they will not be reachable.
Change the value of ac:stylesheet to the URI of your XSLT stylesheet. Add the property if it is absent.
Change the value of ac:stylesheet to the URI of your XSLT stylesheet. Add the property if it is absent. The value has to be an absolute URL on the application's own origin.
The stylesheet can either be uploaded as a file or mounted in docker-compose.yml, in the volumes section of the linkeddatahub service. Mounting is useful while developing.
You will need to restart LinkedDataHub's Docker service for the new stylesheet to take effect.
It is rarely necessary to change the stylesheet of an admin application.
diff --git a/docs/user-guide/manage-dataspaces/CreateContextDataspace.webm b/docs/user-guide/manage-dataspaces/CreateContextDataspace.webm deleted file mode 100644 index e799fd4..0000000 Binary files a/docs/user-guide/manage-dataspaces/CreateContextDataspace.webm and /dev/null differ diff --git a/docs/user-guide/manage-packages.ttl b/docs/user-guide/manage-packages.ttl index 8e49902..4ac8a83 100644 --- a/docs/user-guide/manage-packages.ttl +++ b/docs/user-guide/manage-packages.ttl @@ -12,20 +12,18 @@ rdf:value """Step by step guide to installing and uninstalling packages in your LinkedDataHub dataspace.
Version: Packages were introduced in LinkedDataHub 5.2.
+Version: Packages were introduced in LinkedDataHub 5.2. Since 5.10 they are installed declaratively: an application imports a package with a single ldh:import triple in its settings. The dedicated install/uninstall endpoints and the package Actions menu they were driven from are gone.
Package management requires Control access to the administration application. Only users with administrative privileges can install or uninstall packages.
+Package management requires write access to the application's settings document, which in practice means the owner of the dataspace.
Read more about how packages work.
-Important: After installing or uninstalling a package, you must restart the Docker service for XSLT stylesheet changes to take effect:
-docker-compose restart linkeddatahub-
Do not use --force-recreate as that would overwrite the stylesheet file changes.
Installing or uninstalling a package takes effect on the next request — the package ontology joins the application's imports closure and its stylesheet is composed into the application stylesheet. No restart is needed.
Installing a package adds new functionality to your dataspace by importing ontologies, data, and resources.
+Installing a package adds new functionality to your dataspace by importing its ontology and stylesheet.
Uninstalling a package removes its ontologies and resources from your dataspace. User-created data that uses the package vocabulary will remain but may not function correctly.
+Uninstalling a package removes its ontology and stylesheet from your dataspace. Data you created using the package vocabulary remains but may not display or function correctly without the package.
After installing a package, verify that it was installed correctly:
+After installing a package, verify that it was applied:
ldh:import declaration was stored by fetching the settings document:
+ ldh get \\ + -f ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --accept text/turtle \\ + "https://localhost:4443/settings"+
The output contains an ldh:import triple with the package URI as its object.
Packages may include custom XSLT stylesheets that affect how data is displayed. You can further customize the behavior by:
See the Change layout guide for detailed instructions on stylesheet customization.
@@ -122,19 +131,18 @@If package installation fails:
+If the Save or the ldh patch is rejected:
ldt:ontology and ac:stylesheetIf installed package features are not visible:
Navigate the document hierarchy, related results, and backlinks
-- -
-Document tree is a widget that enables quick overview of the application's document hierarchy. Each document is shown as a node in the tree; container documents - can be expanded to reveal the children documents.
-The widget can be accessed by sliding the mouse to the left edge of the screen (on responsive layouts, it is always visible).
-
-
-
In addition to navigating by document hierarchy, LinkedDataHub lets you navigate by class. The Classes list in the left sidebar shows the classes (rdf:type values) that occur in your data, each labelled with the number of its instances and ordered with the most-used classes first.
Class-based navigation is most useful when:
-The classes list is derived from the data itself, so it reflects whatever types are present — no ontology needs to be defined. It respects your access control settings — you'll only see classes and instances you're authorized to access.
-Backlinks are shown in the right-side navigation for every resource in property layout mode. - They display a list of resources which have properties with the current resource as the object.
-This guide describes how the application dataset can be queried using SPARQL.
-The end-user application dataset can be queried using SPARQL 1.1 - endpoint, which is available via link in the navigation bar.
+The end-user application dataset can be queried using the SPARQL 1.1 + endpoint at the application's sparql URL (e.g. https://localhost:4443/sparql). Opening it in the browser renders an + interactive SPARQL editor.
All forms of SPARQL queries are allowed; SPARQL updates are not allowed. A result limit might apply.
For DESCRIBE and CONSTRUCT results, it is possible to switch the
layout mode using a button above to the results.
Search for resources using text keywords
-You can lookup resources by typing a phrase (it does not have to be complete, start with a few letters) into the search box at the top of the left sidebar.
-A dropdown list will appear if there are any matches. Use up/down keys or mouse click to select one of the results, and you will be redirected to its document.
-The matching is done by looking for substrings using SPARQL regex() in common literal properties such as dct:title, rdfs:label, foaf:name etc. You can find the exact query in Queries / Select labelled.
The same widget is used for autocomplete inputs in the create/edit forms.
-
-
-
You can use SPARQL to query data from the application's SPARQL service.
-Replace owner_cert_password with its value from the .env file and execute the following command:
-add-file.sh \\ --b "https://localhost:4443/" \\ --f ./ssl/owner/cert.pem \\ --p "$owner_cert_password" \\ ---title "$title" \\ ---file "$filename" \\ ---content-type "$content_type"+
A file is uploaded to the document that will hold it, so create that document first. Replace owner_cert_password with the value of the corresponding secret and execute the following commands:
+base="https://localhost:4443/" + +doc=$(ldh create-item \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --title "$title" \\ + --container "$base") + +ldh add-file \\ + -b "$base" \\ + -f ./ssl/owner/keystore.p12 \\ + -p "$owner_cert_password" \\ + --title "$title" \\ + --file "$filename" \\ + --content-type "$content_type" \\ + "$doc"+
The command prints the content-addressed URI of the upload. --content-type is optional — the media type is detected from the file when it is not given.
View, compare and restore document versions
+Version history is available in dataspaces with versioning enabled.
+Click the document's last-modified timestamp in the action bar. The + History dialog opens with the document's versions listed newest first, each showing its datetime and the agent who authored it. + The version you are currently viewing is marked.
+Click a version to view the document as it was at that point. A notice banner reminds you that you are viewing a historical version and + links back to the current one. Historical versions are read-only.
+In the History dialog, select a From and a To version to compare. The diff renders on the document page:
+The diff is display state read from the URL — going back and forward re-renders it, and reloading the page falls back to the plain + historical version.
+In the History dialog, click Restore on the version you want to bring back and confirm. The version's + content is written to the live document, so the restore rolls forward as a new version — nothing is rewritten and the versions rolled past + stay in the history.
+Restoring requires write access to the document; the button is not offered on the version you are currently viewing.
+Read more about versioning and the Memento protocol or access the history from the + command line interface.
+