VODSL
VODSL support in the gradle tools
There is a vodslToVodml
task that will convert models authored in vodsl into standard VO-DML.
the configurable properties within the vodml extension are;
- vodslDir - the default is
src/main/vodsl
- vodslFiles - this is set by default to be all the
*.vodsl
files in the vodslDir, but can be individually set.
the task will write the VO-DML files into the vodmlDir
Any dependencies that have VO-DML models within them will have their VO-DML automatically converted to VODSL
and placed in the build/tmp
directory. Any target VODSL files will have to explicitly include the dependencies with a relative path into that directory.
If you want to have the VO-DML generated automatically from the VODSL rather than running this task manually, then
tasks.named("vodmlJavaGenerate") {
dependsOn("vodslToVodml")
}
build.gradle.kts
file would run the task before the Java generation for instance.
Creating VODSL from existing VO-DML
If it is desired to create VODSL from some existing VO-DML then there is a special task that can be run from the
commandline with arguments (i.e. does not have to be configured in the build.gradle
file as it would not be a repeated part of the workflow)
The task has the --dml
parameter to indicate the input VO-DML file and the --dsl
parameter to indicate the output VODSL file.
gradle vodmlToVodsl --dml=models/sample/sample/vo-dml/Sample.vo-dml.xml --dsl=test.vodsl
VODSL language
The VODSL language use the same underlying meta-model as VO-DML but uses a mapping to a syntax that makes it easier for humans to write by hand. It uses a general C/Java-like syntax with the following characteristics;
-
pairs of curly braces representing grouping
-
attribute declarations ending with semi-colons
;
-
line comments introduced by
// comment
-
block comments
/* comment */
-
keywords
model,author,include,package,abstract,primitive,dtype, otype,as,ordered,composition,enum,references,semantic, subset,title,iskey,ofRank
-
attibute names precede their types
-
"documentation strings"
are enforced for all types -
multiplicities are introduced by
@
The syntax of various parts of the language are described in the following sections. For a fuller description of the semantics of the language, the VO-DML standard itself should be consulted.
Model Declaration
The model declaration includes the name of the model its version followed by a description and then a number of authors.
model example (0.1) "description here"
author "Paul Harrison"
author "An Other"
include "IVOA-v1.0.vodsl"
It will almost always be the case that there should be an include statement that includes the standard IVOA VO-DML base model which defines a number of fundamental primitive types. There can be additonal includes to re-use parts of other models.
Packages
Packages may be used to partition the namespace in a model. Is is not required that all definitions live in a package as there is an assumed “unnamed” which exists at the top-level of the model. Packages may be nested.
package p "package" {
package n "nested package" {
}
}
Note that the above fragment is not actually legal without the inner package containing a type definition.
Types
Types are defined by starting with the particular type keyword. Where
appropriate this might be preceded by abstract
and if the type is a
sub-type of another type then after the type name the supertype is
indicated with ->
.
abstract otype ad1 -> base "an abstract subtype "{
}
Primitives
primitive angle "another primitive"
note the lack of a semi-colon at the end of this declaration.
Enumerations
enum options "an enum" {
val1 "first option",
val2 "second option"
}
DataTypes
DataTypes are defined with the “dtype” keyword. This definition also introduces the syntax for attribute definitions, which are defined between the curly braces of the main DataType definition.
dtype myQuant -> ivoa:RealQuantity "a flagged quantity" {
flag : ivoa:boolean "the flag" ;
}
ObjectTypes
ObjectTypes are defined with the “otype” keyword.
otype o1 {
/* the following attribute is a 'natural key' for the otype */
name : ivoa:string iskey "the identifier";
bv : ivoa:anyURI "Description";
/* note use of ^ to be able to
re-use reserved word.*/
^author: ivoa:string "author";
}
This definition also introduces the iskey
attribute modifier to hint
to any code generation systems that this attribute should be regarded as
a “natural key” for the ObjectType and used rather than generating a
surrogate key.
Multiplicities
otype multiplicities "the @ sign introduces a multiplicity"
{
m1 : ivoa:integer @? "0 or 1";
m2 : ivoa:integer @* "0 or many";
m3 : ivoa:integer @+ "1 or many";
m4 : ivoa:integer @[2] "twice (as an array?)";
}
References and Compositions
This example shows the syntax for references and compositions and the difference in their semantics.
/* this referred to otype is not affected by the lifecycle
of other instances in the model */
otype ReferedTo {
test1: ivoa:integer "";
}
/* instances of this contained class will only live
as long as the containing instance. */
otype Contained {
test2: ivoa:string "";
}
otype RCTest {
ref references ReferedTo "";
contained : Contained @+ as composition "";
}
Subsetting
Subsetting is an advanced VO-DML feature, where an attribute of a subtype can be declared to be a particular sub-type of the supertype’s attribute type.
otype subs -> base {
/* note that the requirement to refer to the q attribute of base */
subset base.q as myQuant; //the type of base.q is a supertype of myQuant
}
Scoping
Type names need to be brought into scope by including the model where they are defined, and thereafter they can be referred to by prefixing the type name with the model name followed by a colon. Types defined in the same model as where they are referred to do not need this model prefix.
If the type is futher namepspaced by packages, then to refer to a type in a package the enclosing package names should be separated by periods. The use of a period to separate name parts is also necessary when referring to an attribute of a type - e.g. when subsetting.[^2]
Full example of VO-DSL
The following is the full model from which the sections above took snippets.
/*
* created on 25 Feb 2022
*/
model example (0.1) "description here"
author "Paul Harrison"
author "An Other"
include "IVOA-v1.0.vodsl"
package p "top level package" {
package n "nested package" {
primitive angle "another primitive"
}
}
enum options "an enum" {
val1 "first option",
val2 "second option"
}
dtype aQuant -> ivoa:Quantity "an angle quantity" {
value : p.n.angle "angle";
}
abstract otype base {
q : ivoa:Quantity "a quantity";
}
abstract otype ad1 -> base "an abstract subtype "{
}
otype o1 {
/* the following attribute is a 'natural key' for the otype */
name : ivoa:string iskey "the identifier";
bv : ivoa:anyURI "Description";
/* note use of ^ to be able to
re-use reserved word.*/
^author: ivoa:string "author";
}
dtype myQuant -> ivoa:RealQuantity "a flagged quantity" {
flag : ivoa:boolean "the flag" ;
}
/* it should be noted in this example that
* @* and @+ are not "recommended" for attributes - it
might be better to use composition of otypes - but this is
not always the case */
otype multiplicities "the @ sign introduces a multiplicity"
{
m1 : ivoa:integer @? "0 or 1";
m2 : ivoa:integer @* "0 or many";
m3 : ivoa:integer @+ "1 or many";
m4 : ivoa:integer @[2] "twice (as an array?)";
}
/* this referred to otype is not affected by the lifecycle
of other instances in the model */
otype ReferedTo {
test1: ivoa:integer "";
}
/* instances of this contained class will only live
as long as the containing instance. */
otype Contained {
test2: ivoa:string "";
}
/* this example references and contains the above types */
otype RCTest {
ref references ReferedTo "";
contained : Contained @+ as composition "";
}
/* an example of subsetting */
otype subs -> base {
/* note that the requirement to refer to the q attribute of base */
subset base.q as myQuant; //the type of base.q is a supertype of myQuant
}
/* an example of the syntax for a constraint */
otype constrained {
val : ivoa:integer "just using a natural language constraint"
< "greater than 5" as Natural> ;
}
Rationale for VODSL
VO-DML is the IVOA standard language for creating data models and the standard document details the reasons behind its creation and the advantages of using such a language over other more general languages such as UML. The standard representation of VO-DML is XML and as such it is difficult to edit model instances directly, especially as the XML is a direct representation of the VO-DML meta model. The most common practice envisaged by the standard is that data models are generally created by visual UML tools and then the UML converted to VO-DML via the XMI interchange format. This approach does work, but it has several disadvantages.
-
UML tools tend to have poor interoperability despite the standard XMI interchange format
-
There needs to be a specialized XMI $\Rightarrow$ VO-DML conversion written for each UML tool (and sometimes for each version of a particular tool).
-
It is difficult to “import” an existing VO-DML definition into a particular UML tool.
-
-
Because of this poor interoperability between UML tools it is difficult for authors to collaborate on the creation of a data model
-
even if they are using the same tool and use XMI in a version control system, there is
-
if they are using different UML tools, comprehending what might be small incremental changes in the source becomes impossible.
-
-
Commercial UML tools tend to be expensive, and the free ones less feature rich.
These difficulties were the inspiration for creating VODSL as a new route to producing VO-DML with the following characteristics;
-
Text based for easy management by version control systems.
-
Concise, so that it is easy for direct comprehension by humans.
The VODSL language and its associated tools are version controlled in GitHub as well as some examples of models expressed in VODSL.
Relationship to VO-DML
The diagram in the introduction shows the role that VODSL plays in the VO-DML creation ecosystem - The yellow arrows indicate transformations that can be made programmatically between the different formats, and the green arrows indicate ways in which the source can be edited and the tools that can be used to create or edit that particular representation. It shows that VODSL has a similar role to XMI/UML in the creation of VO-DML, although with one significant advantage in that there is an exact transformation VO-DML$\Rightarrow$VODSL.
VODSL | UML | |
---|---|---|
Easier to perform global refactoring | vs | Easier to visualise the whole model |
Instant validation[^1] | vs | Full validation only after XSLT transformation of XMI |
Easier to merge contributions from two authors textually | vs | Rely on UML tool to have model merging facility |
[^1]: when using the Eclipse plug-in