Legal Notice Data Protection

Roundtrip

This tutorial covers some of the basic features of MCL. We will create a simple information model for books that can then be used to describe a certain collection of books.

Creating an information model

The building blocks for creating information models are in the pnb.mcl.metamodel.standard module.

Note

pnb.mcl.metamodel is a namespace package that is meant to include alternative metamodel implementations in future (which may be available as, e.g., add-ons to MCL). Alternative implementations will provide additional functionality such as undo-redo support for model changes. As such functionality typically has an impact on performance, it is not provided by the standard implementation. In short: use the standard implementation except if additional functionality is required.

A Model is a container for related information. We create a Model that will hold our information model for books:

1from pnb.mcl.metamodel import standard as mm
2BookML = mm.Model(name='BookML', uri='http://www.plants-and-bytes.de/BookML')
3print(BookML)
↳  <Model 'BookML' (http://www.plants-and-bytes.de/BookML)>

The name a the Model should give a hint of what the Model is about. Our model will describe the Book Modeling Language, or 'BookML'. Most building blocks (i.e., those derived from NamedElement) can have a name, and for most of them, the name is required.

The uri of the Model serves as an identifier that should be globally unique. As we (pnb plants & bytes) own the http://www.plants-and-bytes.de domain, there is no risk that some other organization will use the same URI by mistake.

Warning

The uri of a Model is not necessarily a valid web address.

In general, a URI (Uniform Resource Identifier) is just an identifier. In certain settings, it may be useful to actually publish a Model under its URI – which would then be a URL (Uniform Resource Locator). For instance, see Wikipedia for the distinction between URIs and URLs.

As our information model will cover books, it is straightforward to create a corresponding Class. In our simple model, a ConcreteClass shall suffice:

4Book = mm.ConcreteClass(name='Book')
5print(Book)
↳  <ConcreteClass 'Book'>

We can now add the new class to the model:

6BookML.add(Book)
7print(Book)
↳  <ConcreteClass 'BookML.Book'>

Note that the string representation of Book has changed: it knows that it is now part of the model. Vice versa, we can get the Book class from the model via its name:

8print(BookML.Book)
↳  <ConcreteClass 'BookML.Book'>
9print(Book is BookML.Book)
↳  True

Thus, there is in general no need to keep local names for the elements added to a model.

Note

This namespace concept applies to most classes in the metamodel. For example, also the ConcreteClass BookML.Book is a namespace that provides access to its sub-elements by name.

To cover the title of a book, we add the following DataProperty to Book:

10BookML.Book.add(mm.DataProperty(
11    name='Title', type_=str, lower=1, upper=1))
12print(BookML.Book.Title)
↳  <DataProperty 'BookML.Book.Title'>

The type_ of the new Property is str, the standard Python type for strings. If we give a title for a book, it must be a string; anything else would not be acceptable.

lower and upper are the lower and upper limit of the multiplicity of the Title DataProperty:

  • lower means that a Book must have at least 1 value for Title;

  • upper means that a Book must have at most 1 value for Title.

In consequence, a Book must have exactly 1 value for Title.

A DataProperty is suitable if the type of the code:Property is a DataType, including Python’s built-in str, int, and float.