DCTAP#

This chapter is a short introduction to DCTAP using rudof.

Preliminaries: install and configure rudof#

%pip install -q "pyrudof>=0.3.22"
Note: you may need to restart the kernel to use updated packages.

What is DCTAP?#

DCTAP (Dublin Core Tabular Application Profiles) is a way of writing down an application profile (a model) as a table. One row per property, one group of rows per shape, and a fixed set of column names with defined meanings.

That sounds modest, and the point is precisely that it is. Domain experts who will never write ShEx or SHACL by hand are perfectly comfortable in a spreadsheet, and a spreadsheet is something you can put in front of a room of people and edit together. DCTAP makes that spreadsheet a source artefact: rudof reads it and generates the ShEx or SHACL that machines will actually validate against.

The core columns are:

Column

Meaning

shapeId

the shape this row belongs to; blank means “same as the row above”

propertyId

the property being described

mandatory

must the property be present?

repeatable

may it appear more than once?

valueDatatype

the datatype the value must have

valueShape

the shape the value must conform to

valueConstraint

a literal value, list or pattern the value must match

Reading a profile#

Nothing here needs configuring: reading a table and inspecting it is a self-contained job. (Converting it into a schema does need to know which IRIs the bare names stand for, which is what the converting chapter sets up.)

from pathlib import Path
from tempfile import TemporaryDirectory

from pyrudof import Rudof

tmpdir = TemporaryDirectory()
rudof = Rudof()

Here is a small profile describing people and companies. This is exactly what a CSV export from a spreadsheet looks like:

dctap_str = """shapeId,propertyId,mandatory,repeatable,valueDatatype,valueShape
Person,name,true,false,xsd:string,
,birthdate,false,false,xsd:date,
,worksFor,false,true,,Company
Company,name,true,false,xsd:string,
,employee,false,true,,Person
"""

rudof.read_dctap(dctap_str)

Note how the blank shapeId cells work: birthdate and worksFor belong to Person because the rows above them do. That is what keeps the table readable for a human editing it.

serialize_dctap shows how rudof understood the profile. This is the place to check that your columns were interpreted the way you meant:

print(rudof.serialize_dctap())
Shape(Person)  
 name xsd:string 
 birthdate xsd:date ?
 worksFor @Company *
Shape(Company)  
 name xsd:string 
 employee @Person *

The mandatory and repeatable columns have already become cardinalities: name is required and single-valued, birthdate is optional (?), and worksFor is optional and repeatable (*).

ResultDCTapFormat offers a JSON rendering as well, which carries the source line numbers and is the useful one when you are building tooling around a profile:

from pyrudof import ResultDCTapFormat

print([str(f) for f in ResultDCTapFormat.all()])
print(rudof.serialize_dctap(ResultDCTapFormat.Json)[:500], "...")
['Internal', 'Json']
{
  "version": "0.1",
  "shapes": [
    {
      "shapeID": {
        "str": "Person",
        "line": 2
      },
      "shapeLabel": null,
      "statements": [
        {
          "propertyID": {
            "str": "name",
            "line": 2
          },
          "mandatory": true,
          "repeatable": false,
          "valueDataType": [
            {
              "str": "xsd:string",
              "line": 2
            }
          ]
        },
        {
          "propertyID": {
       ...

Reading from a file#

Profiles usually live in a file rather than in a string. read_dctap accepts a path, and DCTapFormat names the supported input formats:

from pyrudof import DCTapFormat

print([str(f) for f in DCTapFormat.all()])
['Csv', 'Xlsx', 'Xlsb', 'Xlsm', 'Xls']
profile_path = Path(tmpdir.name) / "profile.csv"
profile_path.write_text(dctap_str)

with Rudof() as session:
    session.read_dctap(profile_path, DCTapFormat.Csv)
    print(session.serialize_dctap())
Shape(Person)  
 name xsd:string 
 birthdate xsd:date ?
 worksFor @Company *
Shape(Company)  
 name xsd:string 
 employee @Person *

What to do with a profile#

A profile is a source artefact, not an end in itself. Once rudof has read one, the Comparing and converting schemas chapter takes it the rest of the way: convert_schemas turns the table into a real ShEx schema that validates data, and into a UML-like class diagram for reviewing the model with the people who wrote it.

tmpdir.cleanup()

References#

  • DCTAP - the specification, including the full list of element names.

  • DCTAP primer - a worked introduction.