| SPDX-FileCopyrightText | SPDX-License-Identifier |
|---|---|
2024-2025 SPDX Project |
Community-Spec-1.0 |
The SPDX 3 model is written in a constrained subset of a Markdown markup language*, with predefined headings.
This document provides guidelines for writing model files in the specific syntax used by SPDX 3.
Following these guidelines ensures consistency and avoids rendering issues when using spec-parser and MkDocs to generate model ontologies and model textual specifications.
- Overview
- Directory organisation
- Naming convention
- File content structure and formatting
- Syntax
- Verbal forms for expressions of provisions
- Writing style
- Translation
- Checking if everything is ok
Each model element (class, datatype, individual, property, and vocabulary) is defined in a distinct file.
Specific headings and formatting are used to provide information for the generation of a machine-readable specification, in Resource Description Framework (RDF) data model, by the spec-parser.
For instance, a summary listed under the "Summary" heading will be represented
as a rdfs:comment in the RDF file. Likewise, a value specified for the
"minCount" of a property under the "Properties" heading will be
translated into a sh:minCount in the RDF file.
See an example.
Descriptions provided under the "Description" heading are intended for human reference and will not be incorporated into the RDF file.
The same Markdown files are used to generate the HTML files for the website.
*The Markdown flavour used for the specification is Python-Markdown as it is used by the MkDocs site generator. It differs slightly from the GitHub Flavored Markdown Spec. Running markdownlint over your Markdown files can help enforce formatting consistency and reduce the risk of rendering issues.
Apart from the content in each individual file, the file itself has to be placed in a specific location, as the spec-parser implies some model semantic from the location of the file:
- Each element (class, datatype, individual, property, and vocabulary) is defined in a distinct file.
- Model file names are case-sensitive and shall be identical to the element they represent.
- All model files shall be located within the
model/directory. - Profiles should be organised into subdirectories (e.g.,
Core/,Dataset/). - Elements should be categorised by their type in subdirectories (e.g.,
Classes/,Datatypes/,Individuals/,Properties/,Vocabularies/).
File and directory organisation:
.
├── model
: :
│ ├── Core
│ │ ├── Classes
: : : :
│ │ │ └── Tool.md
│ │ ├── Datatypes
: : : :
│ │ │ └── SemVer.md
│ │ ├── Individuals
: : : :
│ │ │ └── NoneElement.md
│ │ ├── Properties
: : : :
│ │ │ └── verifiedUsing.md
│ │ └── Vocabularies
: : :
│ │ └── SupportType.md
│ ├── Dataset
: :
The living repository at https://github.com/spdx/spdx-3-model/tree/main/model is the best reference.
- Use the singular form (e.g., use
importand notimports). (See discussion in Issue 226) - Use
UpperCamelCaseformat for the names of classes, datatypes, individuals, and vocabularies. - Use
lowerCamelCaseformat for the names of properties and vocabulary entries.
Each model file shall adhere to a strict content structure:
- All files shall be encoded in UTF-8.
- Each file shall start with SPDX license information:
SPDX-License-Identifier: Community-Spec-1.0and follows by one blank line. - The content immediately after the license information shall begin with an H1 heading containing the element's name.
- Each element type has a predefined set of allowed H2 headings and labeled lists that shall be used to structure its content.
- Headings shall be in sentence case (i.e., only the first letter of the first word is capitalized).
Additionally, since MkDocs uses a strict Python-Markdown, each model file shall adhere to specific formatting guidelines:
- Blank lines:
- There shall be a blank line before and after a heading.
- There shall be a blank line before and after a list.
- Indentation:
- Use spaces instead of tabs.
- When a list item consists of multiple paragraphs, each subsequent paragraph in a list item shall be indented by 4 spaces. This applies to any block-level elements nested in a list, including paragraphs, sub-lists, blockquotes, code blocks, etc.
This example is taken from the actual file for
SimpleLicensingText
class.
Its name and location in the repository is
model/SimpleLicensing/Classes/SimpleLicensingText.md.
SPDX-License-Identifier: Community-Spec-1.0
# SimpleLicensingText
## Summary
A license or addition that is not listed on the SPDX License List.
## Description
A SimpleLicensingText represents a License or Addition that is not listed on
the [SPDX License List](https://spdx.org/licenses),
and is therefore defined by an SPDX data creator.
## Metadata
- name: SimpleLicensingText
- SubclassOf: /Core/Element
- Instantiability: Concrete
## Properties
- licenseText
- type: xsd:string
- minCount: 1
- maxCount: 1will give this RDF graph (in Turtle syntax):
<https://spdx.org/rdf/3.1/terms/SimpleLicensing/SimpleLicensingText> a owl:Class,
sh:NodeShape ;
rdfs:comment "A license or addition that is not listed on the SPDX License List."@en ;
rdfs:subClassOf <https://spdx.org/rdf/3.1/terms/Core/Element> ;
sh:nodeKind sh:IRI ;
sh:property [ sh:datatype xsd:string ;
sh:maxCount 1 ;
sh:minCount 1 ;
sh:nodeKind sh:Literal ;
sh:path <https://spdx.org/rdf/3.1/terms/SimpleLicensing/licenseText> ] .The name of a class shall be in UpperCamelCase format.
Allowed headings:
- Summary
- Description
- Metadata
- name: <class_name>
- SubclassOf: <class_name> OR "none" (Shall have one if Instantiability is "Concrete")
- Instantiability: "Abstract" OR "Concrete" (Default: Concrete)
- Properties (Optional)
- <property_name>
- type: <datatype_name>
- minCount: <number> (Optional)
- maxCount: <number> (Optional)
- ...
- <property_name>
- External properties restrictions (Optional)
- <external_property_name>
- minCount: <number> (Optional)
- maxCount: <number> (Optional)
- ...
- <external_property_name>
minCount and maxCount indicate the minimum and maximum number of times
a property may appear in a class (cardinality):
- The minimum possible occurrence is zero (
0). - An unbounded maximum occurrence is represented by a star/asterisk (
*). - If
minCountis omitted, it defaults to0. - If
maxCountis omitted, it defaults to*.
See details in the Conformance section of the specification.
SPDX-License-Identifier: Community-Spec-1.0
# Bot
## Summary
An automated agent.
## Description
A class example.
## Metadata
- name: Bot
- SubclassOf: Agent
- Instantiability: Concrete
## Properties
- prohibitedTask
- type: xsd:string
- minCount: 1
## External properties restrictions
- /Core/Element/name
- minCount: 1The name of a datatype shall be in UpperCamelCase format.
Allowed headings:
- Summary
- Description
- Metadata
- name: <datatype_name>
- SubclassOf: <class_name>
- Format
- pattern: <regular_expression>
SPDX-License-Identifier: Community-Spec-1.0
# DateTime
## Summary
A string representing a specific date and time.
## Description
A DateTime is a string representation of a specific date and time.
## Metadata
- name: DateTime
- SubclassOf: xsd:dateTimeStamp
## Format
- pattern: ^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$The name of an individual shall be in UpperCamelCase format.
Allowed headings:
- Summary
- Description
- Metadata
- name: <individual_name>
- type: <class_name>
- IRI: <IRI>
- Property Values
- <property_name>: <property_value>
- ...
SPDX-License-Identifier: Community-Spec-1.0
# NoneElement
## Summary
A named individual example.
## Description
A named individual of Element class that representing none.
## Metadata
- name: NoneElement
- type: Element
## Property Values
- name: "NONE"The name of a property shall be in lowerCamelCase format.
Allowed headings:
- Summary
- Description
- Metadata
- name: <property_name>
- Nature: "DataProperty" OR "ObjectProperty"
- Range: <datatype_name> OR <class_name>
SPDX-License-Identifier: Community-Spec-1.0
# sensor
## Summary
Describes a sensor used for collecting the data.
## Description
Describes a sensor that was used for collecting the data
and its calibration value as a key-value pair.
## Metadata
- name: sensor
- Nature: ObjectProperty
- Range: /Core/DictionaryEntryThe name of a vocabulary shall be in UpperCamelCase format.
Allowed headings:
- Summary
- Description
- Metadata
- name
- Entries
- <entry_name>: <entry_description>
- ...
Entry formatting:
- Entry names shall be in
lowerCamelCaseformat. - Each entry shall be written on a single line.
- Entries should be listed alphabetically whenever possible to facilitate review and editing, particularly for long lists.
SPDX-License-Identifier: Community-Spec-1.0
# RpsType
## Summary
Specifies the hand shapes used in Rock-Paper-Scissors.
## Description
RpsType specifies the type of a hand shape.
## Metadata
- name: RpsType
## Entries
- paper: A flat, open hand.
- rock: A closed fist.
- scissors: Two fingers extended, forming a V shape.When formulating a provision, the following verbal forms shall be used to express the necessary level of normativity, as defined in ISO/IEC Directives, Part 2 -- Principles and rules for the structure and drafting of ISO and IEC documents:
| Verbal forms | Type of provision |
|---|---|
| shall / shall not | Requirement |
| should / should not | Recommendation |
| may | Permission (do not use "can", "might", "possible", or "impossible" in this context) |
| can / cannot | Possibility and capability |
| must | External constraint |
Equivalent phrases or expressions may be used in certain cases, provided they maintain the exact meaning and level of normativity established by these verbal forms.
See the ISO/IEC Directives for definitions of provisions (Clause 3.3) and verbal forms for expressions of provisions (Clause 7).
To ensure clear and consistent documentation generation, follow these recommendations when writing paragraph text and incorporating links.
-
Avoid overly long paragraphs.
Breaking up text into smaller paragraphs, using bullet points, or creating numbered lists can significantly improve readability and comprehension by separating distinct concepts, processes, criteria, or categories.
This makes the specification easier to scan and understand.
-
Maintain a consistent style.
- Use a uniform writing style, particularly when presenting similar information.
- Use parallel sentence structures for related entries.
This improves readability and helps in comparing related information.
Here's an example of a consistent writing style:
## Entries - crl: Certificate Revocation List, or CRL, is a list of ... - ocsp: Online Certificate Status Protocol, or OCSP, is a common ... - tls: Transport Layer Security, or TLS, is a widely ...
Here's an example of an inconsistent writing style:
## Entries - crl: Certificate Revocation List (CRL) - A CRL is a list of ... - ocsp: OCSP (Online Certificate Status Protocol) is a common ... - tls: Transport Layer Security, or TLS, is a widely ...
-
Avoid bare URLs.
Always provide a descriptive label for each link. Avoid using bare URLs.
This improves accessibility for screen readers and provides context for users.
Here's an example of a recommended link using descriptive text:
[SPDX Project](https://spdx.dev/)
Here's an example of a not recommended bare URL:
https://spdx.dev/ -
Bare URLs: Use with caution.
While descriptive link text is generally preferred for better readability and accessibility, there may be specific instances where bare URLs might be necessary. This could include cases where URLs need to be clearly visible in both digital and print formats or when the URL serves as a metadata value.
The IRI field in the Metadata section shall use a bare URL:
## Metadata - name: SpdxOrganization - type: Organization - IRI: https://spdx.org/
Be aware that MkDocs will not automatically convert bare URLs into clickable links.
To ensure that URLs remain clickable on the specification website, you should enclose them within angle brackets (
<and>).Here's an example of a clickable URL:
SPDX Project GitHub: <https://github.com/spdx/>
Here's an example of an unclickable URL:
SPDX Project GitHub: https://github.com/spdx -
Standard format for RFC URLs.
When referencing RFCs (Request for Comments) or other relevant IETF documents, utilize the following format for the URL:
https://datatracker.ietf.org/doc/<number>/Here's an example of a correct link to an RFC:
[RFC 3986](https://datatracker.ietf.org/doc/rfc3986/)
Here are examples of incorrect links to RFCs:
Incorrect. Missing trailing slash:
[RFC 3986](https://datatracker.ietf.org/doc/rfc3986)
Incorrect. Linking to HTML version:
[RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)
Incorrect. Using a different website:
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986)
-
Code Highlighting.
When using code blocks, specify the appropriate computer language code. For instance, use
jsonfor JSON,yamlfor YAML, andtextfor plain text.This ensures correct syntax highlighting and improves readability.
For example, start a JSON code block with this markup:
```json
A code block with a specified language will be rendered with syntax highlighting, appearing as follows:
{ "type": "Relationship", "from": "urn:spdx.dev:28984", "to": ["urn:acme-4.2"] }A code block without a specified language will be rendered without syntax highlighting, appearing as follows:
{ "type": "Relationship", "from": "urn:spdx.dev:28984", "to": ["urn:acme-4.2"] }
Model summaries, descriptions, and vocabulary entry descriptions can be translated. Please see translation.md for details.
To check if your additions or edits are correctly formatted, according the latest spec-parser, use the following commands.
Install spec-parser:
git clone --branch main --depth 1 https://github.com/spdx/spec-parser.gitIf you already have the spec-parser, update it:
git pull origin mainCheck format:
python3 spec-parser/main.py --no-output <MODEL_MARKDOWN_DIR>Generate RDF, so you can check the RDF outputs:
python spec-parser/main.py --generate-rdf --output-rdf <OUTPUT_RDF_DIR> <MODEL_MARKDOWN_DIR>More spec-parser options:
python spec-parser/main.py --helpTo generate the whole specification website and see how your additions or edits will look like, post-MkDocs processing, read build.md on the spdx-spec repo.