ISO/IEC JTC1/SC34

ISO/IEC

ISO/IEC JTC1/SC34

Information Technology —

Document Description and Processing Languages

Title: Topic Maps Constraint Language
Source: Graham Moore, Dmitry Bogachev, JTC1 / SC34
Project: ISO 19756: Topic Maps Constraint Language
Project editor: Graham Moore, Dmitry Bogachev
Status: Final Committee Draft
Action: For review
Date: 2009-06-16
Summary:
Distribution: SC34 and Liaisons
Refer to:
Supercedes:

Topic Maps Constraint Language

Contents

1 Scope
2 Normative references
3   Notation and Conventions
3.1   General
3.2   tmdm:subject
3.3   Following an Association
3.4   Following an Association to Roles of Given Type
3.5   Playing a Role
3.6   Being a Subtype
3.7   Being an Instance
3.8   Matching a Regular Expression
3.9   The Value of an Occurrence
4   Validation Semantics
5   TMCL Syntax
6   TMCL Declarations
6.1   General
6.2   Topic Type
6.3   Name Type
6.4   Occurrence Type
6.5   Association Type
6.6   Role Type
6.7   Overlap Declaration
7   TMCL Constraint Types
7.1   General
7.2   Abstract Topic Type Constraint
7.3   Subject Identifier Constraint
7.4   Subject Locator Constraint
7.5   Topic Name Constraint
7.6   Topic Occurrence Constraint
7.7   Role Player Constraint
7.8   Scope Constraint
7.9   Reifier Constraint
7.10   Association Role Constraint
7.11   Other Role Constraint
7.12   Occurrence Data Type Constraint
7.13   Unique Value Constraint
7.14   Regular Expression Constraint
8   Additional TMCL Templates
9   User-defined Constraints
9.1   General
9.2   Denial Constraint
10   Schema Documentation
10.1   General
10.2   The Schema Topic
10.3   Documentation Occurrences
11   Conformance
A   TMCL Templates CTM
B   TMCL meta-schema

Foreword

ISO (the International Organization for Standardization) and IEC (the International Electrotechnical Commission) form the specialized system for worldwide standardization. National bodies that are members of ISO or IEC participate in the development of International Standards through technical committees established by the respective organization to deal with particular fields of technical activity. ISO and IEC technical committees collaborate in fields of mutual interest. Other international organizations, governmental and non-governmental, in liaison with ISO and IEC, also take part in the work. In the field of information technology, ISO and IEC have established a joint technical committee, ISO/IEC JTC 1.

International Standards are drafted in accordance with the rules given in the ISO/IEC Directives, Part 2.

ISO/IEC 19756 was prepared by Joint Technical Committee ISO/IEC JTC 1, Information Technology, Subcommittee SC 34, Document Description and Processing Languages.

Introduction

TMCL is a constraint language for Topic Maps, allowing definitions of Topic Maps ontologies and vocabularies to be written in a precise and machine-readable form. This makes it possible to validate a topic map against a TMCL schema to see if it conforms to the constraints in the schema, and also enables a number of other uses, such as schema-driven editors, object mappings, and so on.

TMCL is defined as a Topic Maps vocabulary consisting of a number topic, association, occurrence, and role types, identified by Published Subject Identifiers (PSIs), and defined using English prose. TMCL defines the concept of validation, by which a given topic map is valid according to a schema if it conforms to all the constraints in that schema and a number of additional constraints which apply to all topic maps independent of schema.

TMCL does not have any syntax of its own, since it is defined simply as a Topic Maps vocabulary. However, a number of CTM templates are defined in this standard in order to facilitate authoring of TMCL schemas using CTM.

Topic Maps Constraint Language

1 Scope

This International Standard defines a Topic Maps vocabulary for representing constraints on Topic Maps ontologies, defined using English prose. The vocabulary is defined in terms of validation, that is, verifying whether or not a given topic map conforms to the constraints. It may have many other applications, but these are not described in this International Standard.

2 Normative references

The following referenced documents are indispensable for the application of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

NOTE:

Each of the following documents has a unique identifier that is used to cite the document in the text. The unique identifier consists of the part of the reference up to the first comma.

TMDM, ISO 13250-2:2006 Information Technology — Document Description and Processing Languages — Topic Maps — Data Model, ISO, 2006, http://www.isotopicmaps.org/sam/sam-model/

TMQL, ISO 18048 Information Technology — Document Description and Processing Languages — Topic Maps — Query Language, ISO, http://www.isotopicmaps.org/tmql/

CTM, ISO 13250-5 Information Technology — Document Description and Processing Languages — Topic Maps — Compact Syntax, ISO, http://www.isotopicmaps.org/ctm/

XML Schema-2, XML Schema Part 2: Datatypes Second Edition, W3C Recommendation, 28 October 2004, http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/

3 Notation and Conventions

3.1 General

The TMCL validation rules are defined using constructs from TMDM ([TMDM]), and their meanings are given in English prose following certain conventions, whereby some of the phrases in the text have particular interpretations. These phrases and their interpretations are given in the following clauses.

Throughout this clause the defined phrases contain placeholders given as variables (written thus: v) in the definitions. When the phrases are used, these placeholders are defined either by reference to topics already defined in the context where the phrase is used, or using a qname (an identifying token of the form foo:bar). Qnames are expanded into full IRIs using the prefix declarations in Clause 5, and refer to the topic item which has that IRI in its [subject identifiers] property.

3.2 tmdm:subject

The topic tmdm:subject represents the concept of a subject as defined in [TMDM], and so is the topic type of which all topics are instances, and the common supertype of all topic types. In TMCL it is used in constraints to make it clear that any topic whatsoever may appear in a particular slot in an ontology.

In order to support this even when topic maps do not contain the implied tmdm:type-instance and tmdm:supertype-subtype associations the validation rules give tmdm:subject special treatment, as described below.

3.3 Following an Association

To follow an association of type at from a topic t means traversing all associations of type at. A is the set of all the association items a in the [parent] properties of all the role items in the [roles played] property of t where a's [type] property contains at or some subtype of at.

The end result of the traversal is the set of topic items in the [player] property of each role item r in a's [roles] property, except where r is contained in t's [roles played] property.

3.4 Following an Association to Roles of Given Type

To follow an association of type at to roles of type rt from a topic t means traversing all associations of type at. A is the set of all the association items a in the [parent] properties of all the role items in the [roles played] property of t where a's [type] property contains at or a subtype of at.

The end result of the traversal is the set of topic items in the [player] property of each role item r in a's [roles] property, except where r is contained in t's [roles played] property, or where r's [type] property does not contain rt or some subtype of rt.

3.5 Playing a Role

A topic t is said to play a role of type rt in an association of type at when t's [roles played] property contains at least one role item r whose [type] property contains rt (or some subtype of rt) and r's [parent] property contains an association item whose [type] property contains at or some subtype of at.

3.6 Being a Subtype

A topic type t1 is said to be an subtype of the topic type t2 if following the association type tmdm:supertype-subtype from t1 to roles of type tmdm:supertype produces either t2 or a subtype of t2. If t2 is tmdm:subject then t1 is a subtype of it even if the necessary tmdm:supertype-subtype associations are not present.

3.7 Being an Instance

A topic t is said to be an instance of the topic type tt if following the association type tmdm:type-instance from t produces either tt, a subtype of tt, or if tt is tmdm:subject.

3.8 Matching a Regular Expression

A string s matches a regular expression r if the string is a member of the set of strings L(r) denoted by r as defined in [XML Schema-2].

Ed. Note:

An alternative might be to use the ERE syntax defined in http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap09.html

3.9 The Value of an Occurrence

The value of a topic t's occurrence of type ot is referred to as v, and produced by finding the occurrence item o in t's [occurrences] property whose [type] property contains ot or some subtype of ot. If no such occurrence exists there is no given value. It is an error if there is more than one such occurrence.

4 Validation Semantics

This International Standard defines two kinds of rules:

A schema is a set of constraint topics, declaration topics, topic types, association types, role types, name types, and occurrence types contained in a topic map.

Ed. Note:

Should we say something about how to determine the contents of a schema given a topic map? Also, not sure definition below actually works unless schema topic map and topic map to be validated are merged.

A topic map is valid according to a schema if the topic map is valid according to each individual constraint in the schema, and if the topic map is valid according to all the global validation rules specified in this International Standard.

A topic map is valid according to a constraint if the topic map satisifies the constraint validation rule defined for the constraint type of which the constraint topic is an instance.

NOTE:

TMCL does not dictate when constraints should be applied, nor does it state what it means to a controlling application when it is found that a given constraint is violated.

5 TMCL Syntax

TMCL has no syntax of its own, but since TMCL schemas are represented as topic maps, any Topic Maps representation can be used to create a TMCL schema. Throughout this International Standard all examples are given using the CTM syntax [CTM], and to facilitate the authoring of TMCL in CTM a number of templates are defined. These templates exist in a resource http://www.isotopicmaps.org/tmcl/templates.ctm that can be downloaded and included in any CTM file.

To include the TMCL templates the following CTM include directive can be used:

%include http://www.isotopicmaps.org/tmcl/templates.ctm

The following prefixes are used throughout this document:

%prefix tmcl http://psi.topicmaps.org/tmcl/
%prefix tmdm http://psi.topicmaps.org/iso13250/model/
%prefix xsd http://www.w3.org/2001/XMLSchema#

6 TMCL Declarations

6.1 General

TMCL provides a number of constructs known as declarations, which allow Topic Maps constructs to be used in ways which would otherwise be forbidden by the global validation rules. Declarations are in a sense the opposite of constraints, in that their effect is to relax constraints built into TMCL.

6.2 Topic Type

Making a topic an instance of tmcl:topic-type is a declaration that the topic may be used as a topic type.

EXAMPLE:

Declaring person a topic type:

person isa tmcl:topic-type .  

Any topic t which plays a role of type tmdm:type in an association of type tmdm:type-instance, but which is not an instance of tmcl:topic-type, is invalid.

6.3 Name Type

Making a topic an instance of tmcl:name-type is a declaration that the topic may be used as a name type.

EXAMPLE:

Declaring nickname a name type:

nickname isa tmcl:name-type .  

Global Validation Rule: any topic name item n whose [type] property contains a topic item t where t is not an instance of tmcl:name-type is invalid.

6.4 Occurrence Type

Making a topic an instance of tmcl:occurrence-type is a declaration that the topic may be used as an occurrence type.

EXAMPLE:

Declaring date-of-birth an occurrence type:

date-of-birth isa tmcl:occurrence-type .  

Global Validation Rule: any occurrence item o whose [type] property contains a topic item t where t is not an instance of tmcl:occurrence-type is invalid.

6.5 Association Type

Making a topic an instance of tmcl:association-type is a declaration that the topic may be used as an association type.

EXAMPLE:

Declaring that works-for is an association type:

works-for isa tmcl:association-type .  

Global Validation Rule: any association item a whose [type] property contains a topic item t where t is not an instance of tmcl:association-type is invalid.

6.6 Role Type

Making a topic an instance of tmcl:role-type is a declaration that the topic may be used as a role type.

EXAMPLE:

Declaring employee a role type:

employee isa tmcl:role-type .  

Global Validation Rule: any association role item r whose [type] property contains a topic item t where t is not an instance of tmcl:role-type is invalid.

6.7 Overlap Declaration

The tmcl:overlap-declaration is used to declare that the sets of instances of two or more topic types are non-disjoint (that is, that they may overlap). The default is that the instance sets of different topic types are disjoint.

EXAMPLE:

The following declares that the topic types person and employee overlap:

person isa tmcl:topic-type;
  overlaps(employee).

The following CTM template is defined:

def overlaps($tt1, $tt2)
  ?c isa tmcl:overlap-declaration.
  tmcl:overlaps(tmcl:allows : ?c, tmcl:allowed : $tt1)
  tmcl:overlaps(tmcl:allows : ?c, tmcl:allowed : $tt2)
end

Global Validation Rule: the set of all the topic types of which a given topic t is an instance is referred to as TT. t is invalid if there exists a pair of different topics t1 and t2 in TT such that:

7 TMCL Constraint Types

7.1 General

The tmcl:constraint topic type is used as the base type for all topic types that are considered constraint types. It is an abstract type used simply to group the constraint types for ease of schema introspection.

7.2 Abstract Topic Type Constraint

The tmcl:abstract-constraint provides a way to express that a given topic type must not have any direct instances.

EXAMPLE:

The following states that creature is an abstract topic type:

creature isa tmcl:topic-type;
  is-abstract().

The following CTM template is defined:

def is-abstract($tt)
  ?c isa tmcl:abstract-constraint.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

Constraint Validation Rule for all constraints c of type tmcl:abstract-constraint: c applies to a topic type t, which can be found by following associations of type tmcl:constrained-topic-type from the c topic. t violates the constraint if it plays the role of type tmdm:type in any association of type tmdm:type-instance.

7.3 Subject Identifier Constraint

A subject identifier constraint provides a way to constrain the subject identifiers of instances of a given topic type. The constraint specifies:

EXAMPLE:

The following states that topics of type person must have zero or one subject identifier:

person isa tmcl:topic-type;
  has-subject-identifier(0, 1, ".*").

The following CTM template is defined:

def has-subject-identifier($tt, $min, $max, $regexp)
  ?c isa tmcl:subject-identifier-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max;
    tmcl:regexp: $regexp.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

Constraint Validation Rule for all constraints c of type tmcl:subject-identifier-constraint: c applies to a topic type t, which can be found by following the tmcl:constrained-topic-type association from c. The constraint has the following properties:

For each instance i of t the set of its subject identifiers which match r is referred to as S. i violates c if the cardinality of S is lower than min or greater than max (provided max is not undefined).

Ed. Note:

Do we need a global rule?

7.4 Subject Locator Constraint

A subject locator constraint provides a way to constrain the subject locators of instances of a given topic type. The constraint specifies:

EXAMPLE:

The following states that topics of type document must have at least one subject locator:

document isa tmcl:topic-type;
  has-subject-locator(1, *, ".*").

The following CTM template is defined:

def has-subject-locator($tt, $min, $max, $regexp)
  ?c isa tmcl:subject-locator-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max;
    tmcl:regexp: $regexp.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

Constraint Validation Rule for all constraints c of type tmcl:subject-locator-constraint: c applies to a topic type t, which can be found by following the tmcl:constrained-topic-type association from c. The constraint has the following properties:

For each instance i of t the set of its subject locators which match r is referred to as S. i violates c if the cardinality of S is lower than min or greater than max (provided max is not undefined).

Ed. Note:

Do we need a global rule?

7.5 Topic Name Constraint

A topic name constraint provides a way to constrain the type and cardinality of topic names for instances of a given topic type, and has the following properties:

EXAMPLE:

The following states that topics of type person must have exactly one name of type tmdm:topic-name:

person isa tmcl:topic-type;
  has-name(tmdm:topic-name, 1, 1).

The following CTM template is defined:

def has-name($tt, $nt, $min, $max)
  ?c isa tmcl:topic-name-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $nt)
end

Constraint Validation Rule for all constraints c of type tmcl:topic-name-constraint: c applies to a topic type t, which can be found by following associations of type tmcl:constrained-topic-type from c. The constraint has the following properties:

For each instance i of t the set of its topic names of type nt is referred to as N. i violates c if the cardinality of N is lower than min or greater than max (provided max is not undefined).

Global Validation Rule: any topic name n, whose type is referred to as t, is invalid if no constraint c that is an instance of tmcl:topic-name-constraint can be found such that the topic found by following c's tmcl:constrained-statement associations is t.

7.6 Topic Occurrence Constraint

A topic occurrence constraint defines a way to constrain the type and cardinality of occurrences connected to a topic of a given type, and has the following properties:

EXAMPLE:

The following states that topics of type person must have exactly one occurrence of type date-of-birth:

person isa tmcl:topic-type;
  has-occurrence(date-of-birth, 1, 1).

The following CTM template is defined:

def has-occurrence($tt, $ot, $min, $max)
  ?c isa tmcl:topic-occurrence-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $ot)
end

Constraint Validation Rule for all constraints c of type tmcl:topic-occurrence-constraint: c applies to a topic type t, which can be found by following the association of type tmcl:constrained-topic-type from c. The constraint has the following properties:

For each instance i of t the set of its occurrences of type ot is referred to as O. i violates c if the cardinality of O is lower than min or greater than max (provided max is not undefined).

Global Validation Rule: any occurrence o, whose type is referred to as t, is invalid if no constraint c that is an instance of tmcl:topic-occurrence-constraint can be found such that the topic found by following c's tmcl:constrained-statement associations is t.

7.7 Role Player Constraint

A role player constraint defines a way to constrain the type of allowed role players of a given role with a given type in an association of a given type, and has the following properties:

EXAMPLE:

The following states that topics of type person must have exactly one role of type employee in associations of type works-for:

person isa tmcl:topic-type;
  plays-role(employee, works-for, 1, 1).

The following CTM template is defined:

def plays-role($tt, $rt, $at, $min, $max)
  ?c isa tmcl:role-player-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $rt)
  tmcl:constrained-role(tmcl:constrains : ?c, tmcl:constrained : $at)
end

Constraint Validation Rule for all constraints c of type tmcl:role-player-constraint: c applies to a topic type t, which can be found by following the association of type tmcl:constrained-topic-type from c. The constraint has the following properties:

For each instance i of t the set of its roles of type rt is referred to as R. i violates c if the cardinality of R is lower than min or greater than max (provided max is not undefined).

Global Validation Rule: any association role r, whose type is referred to as rt, and the type of whose containing association is referred to as at, is invalid if no constraint c that is an instance of tmcl:role-player-constraint can be found such that the topic found by following c's tmcl:constrained-statement associations is at and such that the topic found by following c's tmcl:constrained-role associations is rt.

7.8 Scope Constraint

A tmcl:scope-constraint constrains the types of topics which may appear in the scope of a name, occurrence, or association of a particular type, and has the following properties:

Ed. Note:

How to get tmcl:scopetype in? What about the negative rule? How do they combine?

EXAMPLE:

The following states that every occurrence of type description must have exactly one topic of type language in its scope:

description isa tmcl:occurrence-type;
  has-scope(language, 1, 1).

The following CTM template is defined:

def has-scope($st, $tt, $min, $max)
  c isa tmcl:scope-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-statement(tmcl:constrains : c, tmcl:constrained : $st)
  tmcl:allowed-scope(tmcl:allows : c, tmcl:allowed : $tt)
end

Constraint Validation Rule for all constraints c of type tmcl:scope-constraint: c applies to a name, occurrence, or association type st, which can be found by following associations of type tmcl:constrained-statement from c. It has the following properties:

For any name, occurrence, or association s of type st the set of topics in its scope which are instances of t is referred to as S. s violates c if the cardinality of S is lower than min or greater than max (provided max is not undefined).

Global Validation Rule: For every topic t in the scope of a name, occurrence, or association s, where s's type is referred to as st, t may be invalid, if the following does not hold. There must exist a constraint c, which must be an instance of tmcl:scope-constraint, where following associations of type tmcl:constrained-statement from c must produce st, and following associations of type tmcl:allowed-scope from c must produce at least one topic type of which t is an instance.

7.9 Reifier Constraint

A tmcl:reifier-constraint constrains whether or not names, occurrence, and associations of a given type may be reified, and if so, what the type of the reifying topic must be. Such constraints have the following properties:

Ed. Note:

This is only from one side. If we say that occurrences of type X must be reified by topics of type Y, wouldn't it be reasonable to be able to say that topics of type Y must reify occurrences of type X?

EXAMPLE:

The following states that occurrences of type date-of-birth may not be reified:

date-of-birth isa tmcl:occurrence-type;
  cannot-have-reifier().

The following CTM templates are defined:

def must-have-reifier($st, $tt)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 1;
    tmcl:card-max: 1.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: $tt)
end

def cannot-have-reifier($st)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 0;
    tmcl:card-max: 0.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: tmdm:subject)
end

def may-have-reifier($st, $tt)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 0;
    tmcl:card-max: 1.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: $tt)
end

Constraint Validation Rule for all constraints c of type tmcl:reifier-constraint: c applies to a statement type st, which can be found by following associations of type tmcl:constrained-statement, and has the following properties:

Any topic t which is an instance of type tt and reifies a name, occurrence, or association s of type st violates c if max is 0.

Any name, occurrence, or association s of type st violates c if min is 1 and either s has no reifier, or s's reifier is not an instance of tt.

Ed. Note:

Do we need a global rule? Don't think so, but must check.

7.10 Association Role Constraint

An association role constraint constrains the number of roles of a particular type that may appear in associations of a given type, and has a number of properties:

EXAMPLE:

The following states that each association of type works-for must have exactly one role of type employee and one of type employer:

works-for isa tmcl:association-type;
  has-role(employee, 1, 1);
  has-role(employer, 1, 1).

The following CTM template is defined:

def has-role($at, $rt, $min, $max)
  ?c isa tmcl:association-role-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $at)
  tmcl:constrained-role(tmcl:constrains : ?c, tmcl:constrained : $rt)
end

Constraint Validation Rule for all constraints c of type tmcl:association-role-constraint: c applies to an association type at, which can be found by following the tmcl:constrained-statement association from c, and has the following properties:

For each association a of type at the set of its roles which are of type rt is referred to as R. a violates c if the cardinality of R is lower than min or greater than max (unless max is undefined).

Global Validation Rule: for all association roles r, r's type is referred to as rt, the association it appears in is referred to as a, and a's type is referred to as at. r is invalid if there is no constraint c that is an instance of tmcl:association-role-constraint such that:

7.11 Other Role Constraint

The tmcl:other-role-constraint provides a way to restrict which combinations of topic types are allowed to appear in associations of a certain type together. The most common use case is for a hierarchical association like contained-in where a continent may contain countries, countries may contain provinces, and provinces may contain cities, but no other combinations (like a city contained directly in a continent) are allowed.

EXAMPLE:

The following states that if the containee is a city then the container must be a province:

contained-in isa tmcl:association-type;
  has-role(containee, 1, 1);
  has-role(container, 1, 1);
  other-role(containee, city, container, province).

The following CTM template is defined:

def constrain-other-role($at, $rt, $tt, $ort, $ott)
  ?c isa tmcl:other-role-constraint.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $at)
  tmcl:constrained-role(tmcl:constrains: ?c, tmcl:constrained: $rt)
  tmcl:constrained-topic-type(tmcl:constrains: ?c, tmcl:constrained: $tt)
  tmcl:other-constrained-role(tmcl:constrains: ?c, tmcl:constrained: $ort)
  tmcl:other-constrained-topic-type(tmcl:constrains: ?c, tmcl:constrained: $ott)
end

Constraint Validation Rule for all constraints c of type tmcl:other-role-constraint: c has the following properties:

Any role r of type ort, which appears in an association of type at, where at contains at least one role whose player is an instance of tt and whose type is rt violates c if r's player is not an instance of ott.

7.12 Occurrence Data Type Constraint

An occurrence data type constraint provides a way to constrain the allowed datatype of an occurrence of a given type.

EXAMPLE:

The following states that all occurrences of type date-of-birth must have the datatype xsd:dateTime:

date-of-birth isa tmcl:occurrence-type;
  has-datatype(xsd:dateTime).

The following CTM template is defined:

def has-datatype($ot, $dt)
  ?c isa tmcl:occurrence-datatype-constraint;
    tmcl:datatype: $dt.
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $ot)
end

Constraint Validation Rule for all constraints c of type tmcl:occurrence-datatype-constraint: c applies to an occurrence type t, which can be found by following the tmcl:constrained-statement association from c. It has a datatype d, which is the value of c's tmcl:datatype occurrence.

Any occurrence o of type t violates constraint c if its datatype is not d.

Ed. Note:

Should there be a global rule as well?

7.13 Unique Value Constraint

The tmcl:unique-value-constraint provides a way to require all names or occurrences of a given type to have different values.

EXAMPLE:

The following states that all occurrences of type email must have different values:

email isa tmcl:occurrence-type;
  is-unique().

The following CTM template is defined:

def is-unique($st)
  ?c isa tmcl:unique-value-constraint.
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $st)
end

Constraint Validation Rule for all constraints c of type tmcl:unique-value-constraint: c applies to a name or occurrence type st, which can be found by following associations of type tmcl:constrained-statement from c. Any two different names or occurrences s1 and s2 of type st violate c if their values are equal.

7.14 Regular Expression Constraint

The tmcl:regular-expression-constraint provides a mechanism for requiring that all values of a given name or occurrence type must match a given regular expression.

EXAMPLE:

The following states that phone-number occurrences must follow a particular syntax:

phone-number isa tmcl:occurrence-type;
  matches-regexp("(+47\s)?\d\d\s\d\d\s\d\d\s\d\d").

The following CTM template is defined:

def matches-regexp($st, $regexp)
  ?c isa tmcl:regular-expression-constraint;
    tmcl:regexp: $regexp.
  
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
end

Constraint Validation Rule for all constraints c of type tmcl:regular-expression-constraint: c applies to a name or occurrence type t, which can be found by following associations of type tmcl:constrained-statement from c. It has a regular expression r, which is the value of c's tmcl:regexp occurrence.

Any name or occurrence of type t whose value does not match the regular expression r violates c.

8 Additional TMCL Templates

This clause defines a number of additional CTM templates, which are strictly speaking redundant, but which aid authoring by simplifying a number of common use cases.

The following template is used to define a binary association type and two role types:

def binary-association($at, $rt1, $rt2)
  $at isa tmcl:association-type;
    has-role($rt1, 1, 1);
    has-role($rt2, 1, 1).

  $rt1 isa tmcl:role-type.
  $rt2 isa tmcl:role-type.
end

The following template is used to define a binary symmetric association type and one role type:

def symmetric-association($at, $rt)
  $at isa tmcl:association-type;
    has-role($rt, 2, 2).

  $rt isa tmcl:role-type.
end

9 User-defined Constraints

9.1 General

In addition to the predefined constraints provided by TMCL it is possible for users to define their own constraints in order to define more detailed limitations which the predefined constraints cannot express. These constraints must all be instances of some subtype of tmcl:userr-defined-constraint. Two such subtypes are provided by TMCL, but it is possible for users to define their own. Each constraint type must provide a TMQL expression which defines the interpretation of the constraint.

tmcl:validation-expression is an occurrence type used on user-defined constraints, which contains a TMQL expression as defined in [TMQL]. Its exact use and meaning depends on the kind of user-defined constraint it is used with, as defined below.

Ed. Note:

define some error message mechanism?

Ed. Note:

What about an assertion constraint, which is violated if nothing is returned? Wait until the denial constraint is fully worked out.

9.2 Denial Constraint

A topic of type tmcl:denial-constraint represents a user-defined constraint whose tmcl:validation-expression must return nothing in order to be satisfied. That is, if the TMQL query in the tmcl:validation-expression returns a non-empty result the constraint is violated.

EXAMPLE:

The following constraint states that a person's date-of-death must be equal to or later than the person's date-of-birth:

c isa tmcl:denial-constraint;
  tmcl:validation-expression "
    // person [ / date-of-birth <= / date-of-death ]
  ".

A constraint c has an attached query q, which is the value of its occurrence of type tmcl:validation-expression. The query q is run against the topic map being validated, and if the query result is non-empty c is violated.

Ed. Note:

This constraint was formulated as a global constraint. However, could use tmcl:constrained-topic-type and attach it to person, then use $this in the query instead, and have the semantics state that it should run through all instances of what it applies to. Is that better? Should we support both alternatives?

If we use tmcl:constrained-topic-type can it also apply to assoc, occurrence etc types?

A benefit of the tmcl:constarined-topic-type approach is that one can define a general, reusable constraint type with a single TMQL query, and then apply it in different places like a normal TMCL constraint.

This needs more thought.

10 Schema Documentation

10.1 General

TMCL provides a number of constructs which do not affect validation in any way, but which provide useful documentation to users. These constructs are defined in this clause.

10.2 The Schema Topic

The tmcl:schema topic type is provided in order to provide a standard mechanism for making assertions about schemas in topic maps. Each topic of this type represents a TMCL schema.

Ed. Note:

Do we require every schema to have at least one such topic? Should it have a subject locator referring to the schema file? Is that frowned upon? Is it assumed that the schema topic refers to the schema in the current topic map? What if there is more than one?

Possible solution: require at least one schema topic for each schema, require connecting assocs if there is more than one, and assume topic represents all constraints if there is just one.

The tmcl:belongs-to-schema association type is used to connect individual constraints and declarations with the schema. This is useful in situations where a single topic map contains more than one schema, in order to track what comes from which schema.

EXAMPLE:

The following has an example of a schema containing a topic type and a constraint on that topic type:

example-schema isa tmcl:schema;
  - "Example schema".

creature isa tmcl:topic-type;
  - "Creature";
  belongs-to(example-schema).

c isa tmcl:abstract-constraint;
  belongs-to(example-schema).

tmcl:constrained-topic-type(tmcl:constrains : c, tmcl:constrained : creature)

The following CTM template is defined:

def belongs-to($construct, $schema)
  tmcl:belongs-to-schema(tmcl:container: $schema, tmcl:containee: $construct)
end

The tmcl:version occurrence type is used to attach some identifier of the schema's version to the schema topic.

EXAMPLE:

The following is an example of using tmcl:version:

example-schema isa tmcl:schema;
  - "Example schema";
  tmcl:version: "1.0".

10.3 Documentation Occurrences

Three occurrence types which may be attached to any TMCL construct to document it are also provided, as described in this clause.

The tmcl:description occurrence type is used to attach a textual description of a TMCL construct to it inside the topic map.

The tmcl:comment occurrence type is used to attach any textual information to a TMCL construct inside the topic map.

The tmcl:see-also occurrence type is used to attach a to a TMCL construct a reference to any kind of external information about that construct.

EXAMPLE:

The following shows example use of all three occurrence types:

creature isa tmcl:topic-type;
  tmcl:description: "A creature is any kind of living organism.";
  tmcl:comment: "Not sure if we need this. Should review.";
  tmcl:see-also: http://en.wikipedia.org/wiki/Creature .

11 Conformance

There are two levels of conformance defined by this International Standard. In order to meet the requirements for Level One conformance, a TMCL processor must be able to:

NOTE:

This implies that level one processors are not required to support TMQL.

In order to satisfy Level Two conformance processors must conform to Level One and in addition also evaluate user-defined constraints.

NOTE:

This implies that level two processors must support TMQL.

A TMCL Templates CTM (normative)

The CTM defined below is the same that can be located online at http://www.isotopicmaps.org/tmcl/templates.ctm

#########################################################################
# TMCL - Topic Maps Constraint Language
# This file defines the set of templates defined in the TMCL standard
# This document is located at http://www.isotopicmaps.org/tmcl/templates.ctm 
# and is normative.
# Draft version of 2009-06-16.
#########################################################################

# prefix declarations
%prefix tmcl http://psi.topicmaps.org/tmcl/
%prefix tmdm http://psi.topicmaps.org/iso13250/model/


# Overlap Declaration
def overlaps($tt1, $tt2)
  ?c isa tmcl:overlap-declaration.
  tmcl:overlaps(tmcl:allows : ?c, tmcl:allowed : $tt1)
  tmcl:overlaps(tmcl:allows : ?c, tmcl:allowed : $tt2)
end

# Abstract Topic Type Constraint
def is-abstract($tt)
  ?c isa tmcl:abstract-constraint.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

# Subject Identifier Constraint
def has-subject-identifier($tt, $min, $max, $regexp)
  ?c isa tmcl:subject-identifier-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max;
    tmcl:regexp: $regexp.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

# Subject Locator Constraint
def has-subject-locator($tt, $min, $max, $regexp)
  ?c isa tmcl:subject-locator-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max;
    tmcl:regexp: $regexp.
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)
end

# Topic Name Constraint
def has-name($tt, $nt, $min, $max)
  ?c isa tmcl:topic-name-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $nt)
end

# Topic Occurrence Constraint
def has-occurrence($tt, $ot, $min, $max)
  ?c isa tmcl:topic-occurrence-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $ot)
end

# Role Player Constraint
def plays-role($tt, $rt, $at, $min, $max)
  ?c isa tmcl:role-player-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-topic-type(tmcl:constrains : ?c, tmcl:constrained : $tt)  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $rt)
  tmcl:constrained-role(tmcl:constrains : ?c, tmcl:constrained : $at)
end

# Scope Constraint
def has-scope($st, $tt, $min, $max)
  c isa tmcl:scope-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-statement(tmcl:constrains : c, tmcl:constrained : $st)
  tmcl:allowed-scope(tmcl:allows : c, tmcl:allowed : $tt)
end

# Reifier Constraint
def must-have-reifier($st, $tt)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 1;
    tmcl:card-max: 1.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: $tt)
end

def cannot-have-reifier($st)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 0;
    tmcl:card-max: 0.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: tmdm:subject)
end

def may-have-reifier($st, $tt)
  ?c isa tmcl:reifier-constraint;
    tmcl:card-min: 0;
    tmcl:card-max: 1.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
  tmcl:allowed-reifier(tmcl:allows: ?c, tmcl:allowed: $tt)
end

# Association Role Constraint
def has-role($at, $rt, $min, $max)
  ?c isa tmcl:association-role-constraint;
    tmcl:card-min: $min;
    tmcl:card-max: $max.
  
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $at)
  tmcl:constrained-role(tmcl:constrains : ?c, tmcl:constrained : $rt)
end

# Other Role Constraint
def constrain-other-role($at, $rt, $tt, $ort, $ott)
  ?c isa tmcl:other-role-constraint.
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $at)
  tmcl:constrained-role(tmcl:constrains: ?c, tmcl:constrained: $rt)
  tmcl:constrained-topic-type(tmcl:constrains: ?c, tmcl:constrained: $tt)
  tmcl:other-constrained-role(tmcl:constrains: ?c, tmcl:constrained: $ort)
  tmcl:other-constrained-topic-type(tmcl:constrains: ?c, tmcl:constrained: $ott)
end

# Occurrence Data Type Constraint
def has-datatype($ot, $dt)
  ?c isa tmcl:occurrence-datatype-constraint;
    tmcl:datatype: $dt.
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $ot)
end

# Unique Value Constraint
def is-unique($st)
  ?c isa tmcl:unique-value-constraint.
  tmcl:constrained-statement(tmcl:constrains : ?c, tmcl:constrained : $st)
end

# Regular Expression Constraint
def matches-regexp($st, $regexp)
  ?c isa tmcl:regular-expression-constraint;
    tmcl:regexp: $regexp.
  
  tmcl:constrained-statement(tmcl:constrains: ?c, tmcl:constrained: $st)
end

# Additional TMCL Templates
def binary-association($at, $rt1, $rt2)
  $at isa tmcl:association-type;
    has-role($rt1, 1, 1);
    has-role($rt2, 1, 1).

  $rt1 isa tmcl:role-type.
  $rt2 isa tmcl:role-type.
end

# Additional TMCL Templates
def symmetric-association($at, $rt)
  $at isa tmcl:association-type;
    has-role($rt, 2, 2).

  $rt isa tmcl:role-type.
end

# The Schema Topic
def belongs-to($construct, $schema)
  tmcl:belongs-to-schema(tmcl:container: $schema, tmcl:containee: $construct)
end

B TMCL meta-schema (normative)

This annex contains a TMCL schema for TMCL in CTM syntax, defining the allowed structure for TMCL schemas.

#########################################################################
# TMCL - Topic Maps Constraint Language
# This file is the TMCL schema that TMCL schemas must follow.
# This document is located at http://www.isotopicmaps.org/tmcl/schema.ctm 
# and is normative.
# Draft version of 2009-06-16.
#########################################################################

%include http://www.topicmaps.org/tmcl/templates.ctm
%prefix tmcl http://psi.topicmaps.org/tmcl/
%prefix tmdm http://psi.topicmaps.org/iso13250/model/
%prefix xsd http://www.w3.org/2001/XMLSchema#

# TOPIC TYPE
tmcl:topic-type isa tmcl:topic-type;
  - "Topic type";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-topic-type, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1);
  plays-role(tmcl:allowed, tmcl:overlaps, 0, *);
  plays-role(tmcl:constrained, tmcl:other-constrained-topic-type, 0, *);
  plays-role(tmcl:allowed, tmcl:allowed-scope, 0, *);
  plays-role(tmcl:allowed, tmcl:allowed-reifier, 0, *);
  overlaps(tmcl:name-type);
  overlaps(tmcl:occurrence-type);
  overlaps(tmcl:association-type);
  overlaps(tmcl:role-type).

# NAME TYPE
tmcl:name-type isa tmcl:topic-type;
  - "Name type";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-statement, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# OCCURRENCE TYPE
tmcl:occurrence-type isa tmcl:topic-type;
  - "Occurrence type";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-statement, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# ASSOCIATION TYPE
tmcl:association-type isa tmcl:topic-type;
  - "Association type";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-statement, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# ROLE TYPE
tmcl:role-type isa tmcl:topic-type;
  - "Role type";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-statement, 0, *);
  plays-role(tmcl:constrained, tmcl:constrained-role, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# OVERLAP DECLARATION
tmcl:overlap-declaration isa tmcl:topic-type;
  - "Overlap declaration";
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:allows, tmcl:overlaps, 2, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# CONSTRAINT
tmcl:constraint isa tmcl:topic-type;
  - "Constraint";
  is-abstract();
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:containee, tmcl:belongs-to, 0, 1).

# CARD-MIN and CARD-MAX
tmcl:card-min isa tmcl:occurrence-type;
  - "Minimum cardinality";
  has-datatype(xsd:integer). # FIXME: ctm:integer

tmcl:card-max isa tmcl:occurrence-type;
  - "Maximum cardinality";
  has-datatype(xsd:integer). # FIXME: ctm:integer
 
# REGEXP
tmcl:regexp isa tmcl:occurrence-type;
  - "Regular expression";
  has-datatype(xsd:string).

# ABSTRACT CONSTRAINT
tmcl:abstract-constraint ako tmcl:constraint;
  - "Abstract constraint";
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1).

# SUBJECT IDENTIFIER CONSTRAINT
tmcl:subject-identifier-constraint ako tmcl:constraint;
  - "Subject identifier constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  has-occurrence(tmcl:regexp, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1).

# SUBJECT LOCATOR CONSTRAINT
tmcl:subject-locator-constraint ako tmcl:constraint;
  - "Subject locator constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  has-occurrence(tmcl:regexp, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1).

# TOPIC NAME CONSTRAINT
tmcl:topic-name-constraint ako tmcl:constraint;
  - "Topic name constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1).

# TOPIC OCCURRENCE CONSTRAINT
tmcl:topic-occurrence-constraint ako tmcl:constraint;
  - "Topic occurrence constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1).

# ROLE PLAYER CONSTRAINT
tmcl:role-player-constraint ako tmcl:constraint;
  - "Role player constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-role, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1).

# SCOPE CONSTRAINT
tmcl:scope-constraint ako tmcl:constraint;
  - "Scope constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1);
  plays-role(tmcl:allows, tmcl:allowed-scope, 1, 1).

# REIFIER CONSTRAINT
tmcl:reifier-constraint ako tmcl:constraint;
  - "Reifier constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1);
  plays-role(tmcl:allows, tmcl:allowed-reifier, 1, 1).

# ASSOCIATION ROLE CONSTRAINT
tmcl:association-role-constraint ako tmcl:constraint;
  - "Association role constraint";
  has-occurrence(tmcl:card-min, 0, 1);
  has-occurrence(tmcl:card-max, 0, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-role, 1, 1).

# OTHER ROLE CONSTRAINT
tmcl:other-role-constraint ako tmcl:constraint;
  - "Other role constraint";
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-role, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-topic-type, 1, 1);
  plays-role(tmcl:constrains, tmcl:other-constrained-role, 1, 1);
  plays-role(tmcl:constrains, tmcl:other-constrained-topic-type, 1, 1).

# OCCURRENCE DATATYPE CONSTRAINT
tmcl:occurrence-datatype-constraint ako tmcl:constraint;
  - "Occurrence datatype constraint";
  has-occurrence(tmcl:datatype, 1, 1);
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1).

tmcl:datatype isa tmcl:occurrence-type;
  - "Datatype";
  has-datatype(xsd:anyURI).

# UNIQUE VALUE CONSTRAINT
tmcl:unique-occurrence-constraint ako tmcl:constraint;
  - "Unique occurrence constraint";
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1).

# REGULAR EXPRESSION CONSTRAINT
tmcl:regular-expression-constraint ako tmcl:constraint;
  - "Regular expression constraint";
  plays-role(tmcl:constrains, tmcl:constrained-statement, 1, 1).
  
# CONSTRAINED TOPIC TYPE
tmcl:constrained-topic-type isa tmcl:association-type;
  - "Constrained topic type";
  has-role(tmcl:constrains, 1, 1);
  has-role(tmcl:constrained, 1, 1).

tmcl:constrains isa tmcl:role-type.
tmcl:constrained isa tmcl:role-type.

# CONSTRAINED STATEMENT
tmcl:constrained-statement isa tmcl:association-type;
  - "Constrained statement";
  has-role(tmcl:constrains, 1, 1);
  has-role(tmcl:constrained, 1, 1);
  constrain-other-role(tmcl:constrains, tmcl:occurrence-datatype-constraint,
                       tmcl:constrained, tmcl:occurrence-type);
  constrain-other-role(tmcl:constrains, tmcl:association-role-constraint,
                       tmcl:constrained, tmcl:association-type);
  constrain-other-role(tmcl:constrains, tmcl:other-role-constraint,
                       tmcl:constrained, tmcl:association-type).
  # FIXME: can't do unique-value-constraint; introduce common supertype?
  # FIXME: regular-expression-constraint: ditto
  # FIXME: scope-constraint also
  # FIXME: reifier-constraint also

# CONSTRAINED ROLE
tmcl:constrained-role isa tmcl:association-type;
  - "Constrained role";
  has-role(tmcl:constrains, 1, 1);
  has-role(tmcl:constrained, 1, 1).

# OVERLAPS
tmcl:overlaps isa tmcl:association-type;
  - "Overlaps";
  has-role(tmcl:allows, 1, 1);
  has-role(tmcl:allowed, 1, 1).

tmcl:allows isa tmcl:role-type.
tmcl:allowed isa tmcl:role-type.

# OTHER CONSTRAINED ROLE
tmcl:other-constrained-role isa tmcl:association-type;
  - "Other constrained role";
  has-role(tmcl:constrains, 1, 1);
  has-role(tmcl:constrained, 1, 1).

# OTHER CONSTRAINED TOPIC TYPE
tmcl:other-constrained-topic-type isa tmcl:association-type;
  - "Other constrained topic type";
  has-role(tmcl:constrains, 1, 1);
  has-role(tmcl:constrained, 1, 1).

# ALLOWED SCOPE
tmcl:allowed-scope isa tmcl:association-type;
  - "Allowed scope";
  has-role(tmcl:allows, 1, 1);
  has-role(tmcl:allowed, 1, 1).

# ALLOWED REIFIER
tmcl:allowed-reifier isa tmcl:association-type;
  - "Allowed reifier";
  has-role(tmcl:allows, 1, 1);
  has-role(tmcl:allowed, 1, 1).
  
# SCHEMA
tmcl:schema isa tmcl:topic-type;
  - "TMCL schema";
  has-occurrence(tmcl:version, 0, 1);
  has-occurrence(tmcl:description, 0, 1);
  has-occurrence(tmcl:comment, 0, *);
  has-occurrence(tmcl:see-also, 0, *);
  plays-role(tmcl:container, tmcl:belongs-to, 0, *).

tmcl:belongs-to isa tmcl:association-type;
  - "Belongs to";
  - "Contains" @container;
  has-role(tmcl:containee, 1, 1);
  has-role(tmcl:container, 1, 1).

# VERSION
tmcl:version isa tmcl:occurrence-type;
  - "Version";
  has-datatype(xsd:string).

# DESCRIPTION
tmcl:description isa tmcl:occurrence-type;
  - "Description";
  has-datatype(xsd:string).

# COMMENT
tmcl:comment isa tmcl:occurrence-type;
  - "Comment";
  has-datatype(xsd:string).

# SEE-ALSO
tmcl:see-also isa tmcl:occurrence-type;
  - "See also";
  has-datatype(xsd:anyURI).