Unofficial Editor's Draft

ODRL Visualisations — basic version

Requirements and patterns for keeping ODRL policies renderable, explainable, and editable by generic tooling.

Introduction

The requirements below make it possible to visualise ODRL policies with generic tooling: one viewer that renders any policy as a readable document, without code per profile or per dataset.

This note assumes valid ODRL 2.2 policies. It lists only the triples a policy needs on top of that, so a viewer can name, group, date, link, and trace what it shows.

Examples are Turtle with the usual prefixes; ex: is an example namespace.

Terms used: needs = without this triple the functionality does not work. should = it works, but reads worse. Nothing here is fatal when missing: the failure mode is always readability. Each section ends with what the triples enable and what is lost without them.

1. Labels

Names come from the data. A tool cannot invent them.

Policies may assume that labels for the ODRL core vocabulary itself are present: for ODRL 2, visualisers ship a standard label bundle.

Example
ex:policy1 odrl:permission [ odrl:action ex:consult ] .
ex:consult rdfs:label "raadplegen"@nl , "consult"@en .
Enables

Tools can show every part of a policy in human words instead of IRIs, in the reader's language, and readers can ask what a term means without leaving the document.

Without it

Readers see an IRI; without a language tag, possibly a label in the wrong language; without a definition, a term is only its name.

Recommendation for ODRL 3 — define the core vocabulary's labels as part of the vocabulary itself.

2. Reusable nodes

Example
ex:offer1     a odrl:Offer ;     odrl:obligation ex:duty1 .
ex:agreement1 a odrl:Agreement ; odrl:obligation ex:duty1 .

ex:duty1 a odrl:Duty ; odrl:action ex:report .
Enables

Tools can show a shared offer term once, instead of repeating it in full on every agreement.

Without it

The same rule text repeats on every agreement, and nothing shows that they all rest on a single offer term.

3. Named collection hierarchies

The members of a large collection are rarely a flat list: they sit in a hierarchy of named levels from the domain, for example series, files, and records in an archive.

Example
ex:series3 a odrl:Asset , ex:Series ; odrl:partOf ex:archive1 .
ex:file12  a odrl:Asset , ex:File ;   odrl:partOf ex:series3 .
ex:record7 a odrl:Asset , ex:Record ; odrl:partOf ex:file12 .

ex:Series rdfs:label "Series"@en .   # labels: section 1
ex:File   rdfs:label "File"@en .
ex:Record rdfs:label "Record"@en .
Enables

Tools can group the members of a large collection under meaningful headings.

Without it

The members can only be shown as one flat group.

A link between two policies is a prov:wasDerivedFrom between two nodes that are both typed as policies, any subclass of odrl:Policy: odrl:Set, odrl:Offer, odrl:Agreement, odrl:Request, odrl:Ticket, odrl:Assertion. The pair of types gives the link its meaning:

From To Meaning
odrl:Agreement odrl:Offer the agreement accepts the offer
odrl:Agreement odrl:Request the agreement answers the request
odrl:Request odrl:Offer the request asks for the offer

A pair that is not in this table still reads generically as "derived from that policy".

Example
ex:offer1     a odrl:Offer .

ex:request1   a odrl:Request ;
    prov:wasDerivedFrom ex:offer1 .               # asks for the offer

ex:agreement1 a odrl:Agreement ;
    prov:wasDerivedFrom ex:offer1 , ex:request1 . # accepts / answers
Enables

Tools can connect each agreement to the offer it accepts, to list the agreements under an offer, and to show where any policy came from.

Without it

The reference reads as a plain document reference.

Recommendation for ODRL 3 — define dedicated properties for these links.

5. Versions and time

Plain ODRL has no version model, so all of this is extra.

Example
ex:policy-v2 a odrl:Agreement ;              # in force
    prov:specializationOf ex:policy ;
    prov:wasRevisionOf ex:policy-v1 ;
    dct:issued "2026-01-15"^^xsd:date ;
    schema:validFrom "2026-02-01"^^xsd:date .

ex:policy-v1 a odrl:Agreement ;              # superseded
    prov:specializationOf ex:policy ;
    dct:issued "2024-05-20"^^xsd:date ;
    schema:validFrom "2024-06-01"^^xsd:date ;
    schema:validThrough "2026-02-01"^^xsd:date .

ex:policy a prov:Entity ;                    # the identity
    dct:title "Access policy"@en .
Enables

Tools can present all versions of a policy as one whole, let the reader move between them, and show which version applies today.

Without it

There is no version navigation and no status.

Recommendation for ODRL 3 — bring versioning into the language itself: policies that change over time are the rule, not the exception, and today every profile has to assemble its own version model from outside vocabularies.

6. Grouping dimensions

When a policy's rules vary along a common axis, the data can declare that axis:

Example
ex:channel a qb:DimensionProperty ; sh:order 1 ;
    rdfs:label "channel"@en .                    # labels: section 1

ex:rule1 odrl:action ex:distribute-print .
ex:distribute-print rdf:value odrl:distribute ;
    odrl:refinement [
        odrl:leftOperand  ex:channel ;
        odrl:operator     odrl:eq ;
        odrl:rightOperand ex:print ] .

ex:rule2 odrl:action ex:distribute-broadcast .   # same shape, ex:broadcast
Enables

Tools can fold a flat list of rules into a hierarchy: one group per value of the dimension, with the variants beneath it.

Without it

The rules show as a flat, repetitive list.

Recommendation for ODRL 3 — define a native marker for left operands that are single-valued per rule (at most one odrl:eq refinement with a single value), so tools can group on them without the borrowed qb:DimensionProperty declaration.

A policy states what must hold; something else realises it, either a technical artifact outside the policy or another element of the policy. A realisation link records which node realises which element, so that relation can be shown instead of guessed.

A realisation link is a prov:wasDerivedFrom whose target gives the link its meaning, the same doctrine as section 4, one level down, aimed at elements rather than at whole policies:

From To Meaning
any node rule with odrl:uid the node realises the rule itself: assignee, action, target
any node named condition the node enforces that condition
named condition odrl:Duty the condition realises the duty

Markers on a rule or a condition. What may be expected of a rule or of one of its conditions is a separate question from what is actually realised, and the data can say it. Two markers borrowed from DPV (the W3C Data Privacy Vocabulary) do that: a deliberate borrowing like qb:DimensionProperty in section 6, and the same punning shape, an extra rdf:type on the instance.

Example
ex:rule1 a odrl:Permission ; odrl:uid ex:rule1 ;
    odrl:action [ rdf:value ex:consult ; odrl:refinement ex:measure1 ] ;
    odrl:constraint ex:cond1 , ex:cond2 ,
        [ odrl:leftOperand ex:trained ] .        # blank: cannot be pointed at

# The realising side, standing in the policy itself. Equally valid: hang the
# same prov:wasDerivedFrom on ex:bundle1 — this section says "any node".
ex:measure1 a odrl:Constraint , dpv:TechnicalMeasure ;
    odrl:leftOperand  ex:request ;
    odrl:operator     ex:conformsTo ;
    odrl:rightOperand ex:bundle1 ;               # what stands behind it
    prov:wasDerivedFrom ex:rule1 , ex:cond1 .

ex:bundle1 a ex:PolicyBundle ;                   # its class is domain
    dct:title "Access bundle"@en .               # vocabulary, not ODRL

ex:cond1 a odrl:Constraint ;                     # unmarked: counts, and is realised
    odrl:leftOperand  ex:searchType ;
    odrl:operator     odrl:eq ;
    odrl:rightOperand ex:byPostcode ;
    prov:wasDerivedFrom ex:duty1 .               # realises the duty

ex:cond2 a odrl:Constraint , dpv:OrganisationalMeasure ;   # applies, does not count
    odrl:leftOperand  ex:timeOfRequest ;
    odrl:operator     ex:within ;
    odrl:rightOperand ex:officeHours .

ex:duty1 a odrl:Duty ; odrl:action ex:restrictSearch .
Enables

Tools can show, per element, what realises it and what it realises in turn, and walk that chain in both directions: from a realising node to the rules and conditions it carries, and from a duty back to the conditions that realise it. Conditions that nothing enforces stay visible, and the markers let a tool say why: technical measure, organisational measure, or simply not enforced.

Without it

Realisation can only be guessed at the level of whole policies, so a partly enforced rule reads as either fully enforced or not at all. Without the markers, every unenforced condition reads as an omission, including the ones nothing was ever going to enforce.

Recommendation for ODRL 3 — define a dedicated property for realisation links (for example realizes, possibly a subproperty of prov:wasDerivedFrom): derivation is generic provenance, and "realises" is load-bearing enough to deserve its own name. Define native markers for a rule or condition that delegates to a technical measure and for one that is secured organisationally, so the borrowing from DPV is not needed.

8. Domain forms

A policy points at domain nodes a generic tool cannot know: the artifact behind a realisation link (section 7), a field collection, a register. Labels (section 1) name such a node; a form shape says how to present its properties.

Example
ex:ArtifactShape a sh:NodeShape ;
  sh:targetClass ex:PolicyArtifact ;
  sh:property [ sh:path rdfs:label ;
    dash:propertyRole dash:LabelRole ] ;
  sh:property [ sh:path rdf:type ;
    sh:name "Soort"@nl , "Kind"@en ;
    sh:order 0 ; dash:viewer dash:LabelViewer ] ;
  sh:property [ sh:path dct:format ;
    sh:name "Formaat"@nl , "Format"@en ;
    sh:order 1 ; dash:viewer dash:LiteralViewer ] ;
  sh:property [ sh:path dcat:downloadURL ;
    sh:name "Download"@nl , "Download"@en ;
    sh:order 2 ; dash:viewer dash:URIViewer ] ;
  sh:property [ sh:path rdfs:comment ;
    sh:name "Noot"@nl , "Note"@en ;
    sh:order 9 ; dash:viewer dash:LangStringViewer ] .
Enables

Tools can show unknown domain nodes as a tidy, ordered, bilingual form (right fields, right order, links as links) without code per profile; when a profile adds a field, the form follows the shape.

Without it

Tools fall back to a bare property list: every triple of the node, in arbitrary order, labelled by section 1 at best.

Recommendation — profiles that define domain classes (such as policy artifacts) should ship a form shape for them alongside the class labels, so every consumer renders the same form.