<https://docs.linkeddatahub.com/reference/administration/ontologies/#content>
        a       <https://w3id.org/atomgraph/linkeddatahub#XHTML>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#value>
                "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n    <p class=\"ldh-body-lg\">Classes, constructors, constraints and properties of the dataspace's domain model</p>\n    <div>\n        <h2 id=\"ontologies\">Ontologies</h2>\n        <p>Ontologies are sets of domain concepts. The domain can span both documents (information resources) and abstract/physical things\n            (non-information resources).</p>\n        <p>Ontologies can <a href=\"https://www.w3.org/TR/owl2-primer/#Ontology_Management\" target=\"_blank\">import other ontologies</a>, both user-defined\n            and system ones provided by LinkedDataHub. The dataspace's <a href=\"../../dataspace/#dataspaces\">namespace ontology</a> is resolved as a native <code>owl:imports</code> union graph —\n            the transitive closure of its imports — which is cached per ontology URI. No inference is materialized: the terms are served exactly as declared.</p>\n        <p>An ontology URI is resolved against the store first and the platform's bundled copies second: a document in the admin dataspace that declares\n            the ontology (<code>&lt;uri&gt; a owl:Ontology</code>) is the graph that resolves, even for a vocabulary the platform ships a copy of. That is what lets\n            an imported vocabulary and its annotations live in one document under the vocabulary's own URI.</p>\n        <p><a href=\"../packages/\">Package</a> ontologies join the dataspace's imports closure automatically. They are derived from the dataspace's\n            <code>ldh:import</code> declarations at ontology load time and declared as <code>owl:imports</code> of the namespace ontology, so they resolve\n            like any other import. On the first request after the import, the package ontology is <dfn>materialized</dfn>: copied verbatim into a document under the\n            admin dataspace's <samp>ontologies/</samp> container, named after the package's path (<samp>ontologies/editor-taxonomy/</samp> for the taxonomy editor),\n            with the ontology as its <code>foaf:primaryTopic</code>. From then on that document is what the closure resolves the package ontology to, and its constructors,\n            constraints and views are edited like the namespace ontology's. A later change to the published package does not reach the dataspace until the document\n            is deleted, after which the next request materializes the package again.</p>\n        <div class=\"ac-alert va-warning\" role=\"status\">\n            <span class=\"ac-alert-ic\"><span aria-hidden=\"true\" class=\"msi outline\">warning</span></span>\n            <div class=\"ac-alert-body\">\n                <span class=\"ac-alert-title\">Best practice: avoid using <code>owl:imports</code> with uploaded files</span>\n                <p class=\"ac-alert-text\">Do not use <code>owl:imports</code> declarations that point to paths under <samp>uploads/</samp>. This can cause circular dependency deadlocks\n                during system initialization, as the ontology loading process cannot access uploaded files without creating a circular reference.</p>\n                <p class=\"ac-alert-text\">Instead:</p>\n                <ul class=\"ac-alert-text\">\n                    <li>Host ontologies as proper documents (not uploaded files)</li>\n                    <li>Import them using their document URIs</li>\n                    <li>If you need to use an ontology that was uploaded, create it as a proper ontology document first</li>\n                </ul>\n                <p class=\"ac-alert-text\">For more information, see the <a href=\"../../../user-guide/upload-file/\">file upload documentation</a>.</p>\n            </div>\n        </div>\n        <p>Main ontology properties:</p>\n        <dl>\n            <dt>Imports</dt>\n            <dd>The URI of another ontology whose terms are pulled into this ontology's imports closure (<code>owl:imports</code>)</dd>\n            <dt>Version</dt>\n            <dd>Version identifier of the ontology (<code>owl:versionInfo</code>)</dd>\n        </dl>\n        <div>\n            <h3 id=\"system-ontologies\">System ontologies</h3>\n            <table>\n                <caption class=\"ac-vh\">System ontologies and their prefixes</caption>\n                <thead>\n                    <tr>\n                        <th scope=\"col\">Ontology</th>\n                        <th scope=\"col\">Title</th>\n                        <th scope=\"col\">Prefix</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub/default\" id=\"def-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub/default#</code></a></td>\n                        <td>Default</td>\n                        <td><code>def:</code></td>\n                    </tr>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub/dataspaces\" id=\"lds-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub/dataspaces#</code></a></td>\n                        <td>Dataspaces</td>\n                        <td><code>lds:</code></td>\n                    </tr>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub/admin/acl\" id=\"lacl-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub/admin/acl#</code></a></td>\n                        <td>Access control</td>\n                        <td><code>lacl:</code></td>\n                    </tr>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub/admin\" id=\"adm-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub/admin#</code></a></td>\n                        <td>Admin</td>\n                        <td><code>adm:</code></td>\n                    </tr>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub\" id=\"ldh-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub#</code></a></td>\n                        <td>LinkedDataHub</td>\n                        <td><code>ldh:</code></td>\n                    </tr>\n                    <tr>\n                        <td><a href=\"https://w3id.org/atomgraph/linkeddatahub/document-hierarchy\" id=\"dh-ont\" target=\"_blank\"><code>https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#</code></a></td>\n                        <td>Document hierarchy</td>\n                        <td><code>dh:</code></td>\n                    </tr>\n                </tbody>\n            </table>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"classes\">Classes</h2>\n        <p>Classes are RDFS/OWL classes declared in the dataspace's namespace ontology. Their instances live in the <a href=\"../../dataset/\">dataspace dataset</a>.</p>\n        <p>The main class properties, explained in the sub-sections below:</p>\n        <dl>\n            <dt><a href=\"#constructors\">Constructors</a></dt>\n            <dd>Queries that construct a new class instance</dd>\n            <dt><a href=\"#constraints\">Constraints</a></dt>\n            <dd>Commands or command templates that validate a class instance</dd>\n        </dl>\n        <div>\n            <h3 id=\"constructors\">Constructors</h3>\n            <p>Constructors are SPARQL <code>CONSTRUCT</code> queries that serve as templates for class instances.\n                They specify the properties (both mandatory and optional) that the instance is supposed to have, as well as expected datatypes of their\n                values. Constructors drive the resource creation and editing forms. A class can have multiple constructors.</p>\n            <p>The Northwind demo wires a constructor onto <code>schema:Product</code>, which is what makes the Product create form offer the right controls:</p>\n            <pre>schema:Product spin:constructor :ProductConstructor ;\n    spin:constraint :MissingName .\n\n:ProductConstructor a ldh:Constructor ;\n    rdfs:label \"Product constructor\" ;\n    dct:title \"Product constructor\" ;\n    sp:text \"\"\"\n        PREFIX schema:  &lt;https://schema.org/&gt;\n        PREFIX dct:     &lt;http://purl.org/dc/terms/&gt;\n        PREFIX xsd:     &lt;http://www.w3.org/2001/XMLSchema#&gt;\n\n        CONSTRUCT {\n            $this dct:title [ a xsd:string ] ;\n                schema:name [ a xsd:string ] ;\n                schema:identifier [ a xsd:string ] ;\n                schema:description [ a xsd:string ] ;\n                schema:category [ a schema:ProductGroup ] ;\n                schema:provider [ a schema:Corporation ] ;\n                schema:offers [ a schema:Offer ] .\n        }\n        WHERE {}\"\"\" ;\n    rdfs:isDefinedBy : .</pre>\n            <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/admin/model/ns.ttl\" target=\"_blank\">admin/model/ns.ttl</a></p>\n            <p>A constructor can also supply a default <em>value</em> — the built-in <code>ldh:XHTML</code> constructor seeds new blocks with an empty XHTML literal:</p>\n            <pre>PREFIX rdf:     &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;\n\nCONSTRUCT {\n  $this rdf:value \"&lt;div xmlns=\\\"http://www.w3.org/1999/xhtml\\\"&gt;&lt;/div&gt;\"^^rdf:XMLLiteral .\n}\nWHERE {}</pre>\n            <p>LinkedDataHub reuses <a href=\"http://spinrdf.org/spin.html#spin-constructors\" target=\"_blank\">SPIN constructors</a> for the implementation, but adds a\n                special syntax convention using blank nodes to indicate the expected resource type (<code>[ a ex:Person ]</code>) or literal datatype\n                (<code>[ a xsd:string ]</code>). The magic variable <code>$this</code> refers to the instance being constructed. It starts as a blank node\n                resource and is skolemized to a URI when the form is submitted to the server.</p>\n            <p>Note that classes inherit constructors from superclasses at runtime. A subclass constructor only needs to declare the properties its\n                superclasses do not already declare.</p>\n            <p>Constructor instances are instantiated client-side: the constructors of the resource's types (including the superclass closure) are expanded\n                onto a single instance. For that to work, a constructor has to have an empty <code>WHERE</code> clause, as in the example above.</p>\n        </div>\n        <div>\n            <h3 id=\"constraints\">Constraints</h3>\n            <p>Constraints validate a document as a write leaves it. Two kinds are supported, and both are checked on every write:\n                <a href=\"https://spinrdf.org/spin.html#spin-constraints\" target=\"_blank\">SPIN constraints</a> — SPARQL queries or\n                <a href=\"https://spinrdf.org/spin.html#spin-templates\" target=\"_blank\">SPIN command templates</a> attached to a class with\n                <code>spin:constraint</code> — and <a href=\"https://www.w3.org/TR/shacl/\" target=\"_blank\">SHACL</a> shapes. A SPIN constraint applies to\n                instances of the class it is declared on and reports violations —\n                missing mandatory properties, malformed values and so on. For example, an instance of\n                <code>dh:Item</code> without <code>dct:title</code> will fail validation because titles are mandatory for LinkedDataHub documents.</p>\n            <p>The most common constraint shape is the missing-property check. The Northwind demo requires every Product to have a name:</p>\n            <pre>:MissingName a ldh:MissingPropertyValue ;\n    rdfs:label \"Missing schema:name\" ;\n    sp:arg1 schema:name ;\n    rdfs:isDefinedBy : .</pre>\n            <p>Submitting a Product without <code>schema:name</code> is then rejected with <samp>422 Unprocessable Entity</samp>, and the response body\n                describes the violation in RDF:</p>\n            <pre>[ a spin:ConstraintViolation ;\n    rdfs:label \"Missing schema:name\" ;\n    spin:violationRoot &lt;#this&gt; ;\n    spin:violationPath schema:name ] .</pre>\n            <p>Classes inherit SPIN constraints from superclasses. SHACL shapes declared in the ontology (or in any ontology of its imports closure) are validated with <a href=\"https://jena.apache.org/documentation/shacl/\" target=\"_blank\">Jena SHACL</a>\n                alongside the SPIN constraints, and a violation is likewise rejected with <samp>422 Unprocessable Entity</samp>.</p>\n            <p>What is validated is the document as it will be written, not the request body alone. A <code>PUT</code> carries the whole document, a\n                <code>POST</code> is checked merged with the triples the document already holds, and a <code>PATCH</code> is checked on the graph its update\n                produces. A <code>PATCH</code> that adds a <code>schema:description</code> to a Product therefore passes without repeating its name, and one that\n                deletes the name is rejected. A <code>PATCH</code> cannot remove a resource's <code>rdf:type</code> either, since that would take the resource\n                out of its class's constraints. <a href=\"../../imports/\">Imports</a> write through the same methods and are held to the same check.</p>\n            <p>A write is rejected whenever the resulting document violates a constraint, including a violation that was there before the write. A document\n                left invalid by a later change to the ontology accepts only a write that repairs every violation it has. The <samp>422</samp> body describes\n                the violating resources alone, not the whole document, so it names what has to be repaired.</p>\n            <p>Constraints are evaluated over the written document's own graph. A constraint cannot look into other documents, and writing another document\n                never re-validates this one.</p>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"properties\">Properties</h2>\n        <p>You can define new properties. Like classes, properties are declared in the dataspace's namespace ontology.\n            The expected values of a property on a class are described either with a SPIN <a href=\"#constraints\">property constraint</a> (a mandatory-property check)\n            or with an OWL <a href=\"#restrictions\">restriction</a>, both of which the creation and editing forms enforce. A property can also carry a\n            <a href=\"#views\">view</a> that lists the resources it relates.</p>\n        <div>\n            <h3 id=\"restrictions\">Restrictions</h3>\n            <p>An <code>owl:Restriction</code> pins the cardinality of a property. The Northwind model, for example, declares its properties with\n                domains and ranges, and pins the sales-rep cardinality with a restriction — every order has exactly one:</p>\n            <pre>schema:broker a owl:ObjectProperty ;\n    rdfs:label \"Sales rep\";\n    rdfs:domain schema:Order ;\n    rdfs:range schema:Person ;\n    rdfs:isDefinedBy : .\n\n[] a owl:Restriction ;\n    owl:onProperty schema:broker ;\n    owl:minCardinality 1 ;\n    owl:maxCardinality 1 ;\n    rdfs:isDefinedBy : .</pre>\n            <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/admin/model/ns.ttl\" target=\"_blank\">admin/model/ns.ttl</a></p>\n        </div>\n        <div>\n            <h3 id=\"views\">Views</h3>\n            <p>A property can carry a <a href=\"../../data-model/views/\">view</a> that lists the resources it relates: <code>ldh:view</code> attaches\n                the view in the property's forward direction, <code>ldh:inverseView</code> in its inverse. The view is stored in no document. LinkedDataHub\n                derives it whenever it renders a resource, and appends it to that resource's row.</p>\n            <p>Which resources get the view is decided by the property's declaration, not by the data. An <code>ldh:view</code> renders on every resource\n                typed with the property's <code>rdfs:domain</code>, an <code>ldh:inverseView</code> on every resource typed with its <code>rdfs:range</code>,\n                and a domain or range inherited through <code>rdfs:subPropertyOf</code> counts as well. The resource does not have to carry the property, and a\n                property with no domain or range never renders its view. In the view's query, <code>$about</code> is bound to the resource the view is\n                rendered on.</p>\n            <p>The Northwind model lists a customer's orders on the customer, through the inverse of <code>schema:customer</code>, whose range is\n                <code>schema:Corporation</code>:</p>\n            <pre>schema:customer a owl:ObjectProperty ;\n    rdfs:domain schema:Order ;\n    rdfs:range schema:Corporation .\n\nschema:customer ldh:inverseView :OrdersFromCustomer .\n\n:OrdersFromCustomer a ldh:View ;\n    dct:title \"Orders from this customer\" ;\n    spin:query :SelectOrdersFromCustomer ;\n    ac:mode ac:TableMode ;\n    ldh:showWhenEmpty false .\n\n:SelectOrdersFromCustomer a sp:Select ;\n    sp:text \"\"\"\n    SELECT DISTINCT ?order\n    WHERE { GRAPH ?graph { ?order schema:customer $about ; schema:orderDate ?orderDate } }\n    ORDER BY DESC(?orderDate)\"\"\" .</pre>\n            <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/admin/model/ns.ttl\" target=\"_blank\">admin/model/ns.ttl</a></p>\n            <p>Since the view renders on every customer, <code>ldh:showWhenEmpty false</code> hides it on a customer that has placed no orders. The view's\n                <code>ac:mode</code> fixes its layout mode, and the view renders a <span class=\"ac-btn in-primary ap-solid sz-md\">Create</span> button for\n                <a href=\"../../data-model/views/#inline-creation\">inline creation</a> of the class at the property's other end.</p>\n            <p>The attachments are read from the namespace ontology and its imports closure, so a view declared in <samp>ns.ttl</samp> and one declared in\n                a <a href=\"../packages/#property-views\">package ontology</a> behave the same. A derived view has no edit or drag controls: it is changed by\n                editing its declaration in the ontology.</p>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"importing-vocabularies\">Importing external vocabularies</h2>\n        <p>The <samp>Import ontology</samp> action loads an external vocabulary into a document of the admin dataspace and derives instance\n            <a href=\"#constructors\">constructors</a> for its classes. The vocabulary stays in that document, under its own URI and with its own header, and the\n            derived constructors are appended beside it; the document names the vocabulary as its <code>foaf:primaryTopic</code> rather than claiming to be an ontology\n            itself. The dataspace's namespace ontology imports the vocabulary URI, which resolves to that document because it declares the vocabulary — so the\n            constructors are edited where the vocabulary is, and nothing has to be re-fetched from the network or a bundled copy.</p>\n        <img alt=\"The Import ontology form, with the vocabulary URI as Source and the target document as Graph\" src=\"/uploads/3ec09a0069882615f5754801ebab899556655cba\"></img>\n        <p>Importing the SKOS vocabulary, for example, leaves the target document with content of this shape (abridged):</p>\n        <pre>&lt;&gt; a dh:Item ;\n    foaf:primaryTopic &lt;http://www.w3.org/2004/02/skos/core&gt; .    # the document is about the vocabulary\n\n&lt;http://www.w3.org/2004/02/skos/core&gt; a owl:Ontology .          # the vocabulary's own header and terms follow\n\nskos:Concept spin:constructor [ a ldh:Constructor ;\n    sp:text \"\"\"\n        PREFIX skos: &lt;http://www.w3.org/2004/02/skos/core#&gt;\n        PREFIX xsd:  &lt;http://www.w3.org/2001/XMLSchema#&gt;\n\n        CONSTRUCT {\n            $this skos:prefLabel [ a xsd:string ] ;\n                skos:broader [ a skos:Concept ] .\n        }\n        WHERE {}\"\"\" ] .                                       # …one derived constructor per class</pre>\n    </div>\n    <div>\n        <h2 id=\"management\">Management</h2>\n        <table>\n            <caption class=\"ac-vh\">Ontology actions and their CLI commands</caption>\n            <thead>\n                <tr>\n                    <th scope=\"col\">Action</th>\n                    <th scope=\"col\">CLI command</th>\n                </tr>\n            </thead>\n            <tbody>\n                <tr>\n                    <th scope=\"row\">Create ontology</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin create ontology</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Import external vocabulary</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin import ontology</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Add ontology import</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin add ontology-import</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Clear ontology from cache</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin clear ontology</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Create class</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin add class</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Add constructor</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin add constructor</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Add property constraint</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin add property-constraint</samp></a></td>\n                </tr>\n                <tr>\n                    <th scope=\"row\">Add restriction</th>\n                    <td><a href=\"../../command-line-interface/#commands\"><samp>ldh admin add restriction</samp></a></td>\n                </tr>\n            </tbody>\n        </table>\n    </div>\n    <p class=\"ldh-body-lg\">To evolve your dataspace's model in practice, follow the <a href=\"../../../user-guide/change-model/\">Change model</a> guide.</p>\n</div>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .

<https://docs.linkeddatahub.com/reference/administration/ontologies/>
        a       <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#Item>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#_1>
                <https://docs.linkeddatahub.com/reference/administration/ontologies/#content>;
        <http://purl.org/dc/terms/created>
                "2026-10-25T17:34:36.652Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>;
        <http://purl.org/dc/terms/creator>
                <https://admin.linkeddatahub.com/acl/agents/01fe43e2-f80e-4312-b37e-86063a80e4f9/#this>;
        <http://purl.org/dc/terms/description>
                "Classes, constructors, constraints and properties of the dataspace's domain model";
        <http://purl.org/dc/terms/modified>
                "2026-10-27T12:17:03.823Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>;
        <http://purl.org/dc/terms/title>
                "Ontologies";
        <http://rdfs.org/sioc/ns#has_container>
                <https://docs.linkeddatahub.com/reference/administration/>;
        <http://www.w3.org/ns/auth/acl#owner>
                <https://admin.linkeddatahub.com/acl/agents/01fe43e2-f80e-4312-b37e-86063a80e4f9/#this> .
