Convert LinkML schemas to XSD 1.0/1.1 and Schematron.
Project description
linkml-to-xsd
Status 0.x — the mapping is exercised by 200+ tests and at parity on a real production schema, but the Python API may still change before 1.0.
A Python library and CLI that converts LinkML schemas into
XML Schema (XSD) — and, for constraints XSD
cannot express, Schematron. Built on
linkml-runtime's SchemaView, so
imports, mixins, slot_usage and inlining are resolved by the reference
implementation rather than re-guessed.
Features
- XSD 1.0 output: classes →
xs:complexType+ global element;is_a→xs:extension(UPA-safe); mixins flattened; enums, user types with facets (pattern,minimum_value,maximum_value); cardinality. - References vs. inlining follow LinkML semantics: a non-inlined class-range
slot with an identifier becomes a reference;
inlined/inlined_as_listproduce nested elements. - Identity constraints:
identifier→xs:key,unique_keys→xs:unique, references →xs:keyref(real referential integrity). - Value constraints:
@defaultfrom literalifabsent,@fixedfromequals_string/equals_number. - Documentation & metadata:
description→xs:documentation,class_uri/slot_uri/enum_uri/meaning→xs:appinfo. - XSD 1.1 (opt-in): class
rulesalso emitted asxs:assert. - Schematron: class
rules(precondition ⇒ postcondition) and boolean combinators (any_of/all_of/exactly_one_of/none_of) as XPath assertions. - Profiles: the eCH-0296 / Akoma Ntoso annotation vocabulary
(
xml_element,xml_attribute,xml_namespace,xsd_mixed,xsd_content_model) via--profile akn— proven at parity on the real Fedlex SR-101. - Example-XML generation and XSD validation helpers.
Installation
From a checkout:
pip install -e ".[dev]"
Released versions are published to PyPI and this project's GitLab package
registry on every vX.Y.Z tag:
# PyPI (recommended)
pip install linkml-xsd
# GitLab package registry
pip install linkml-xsd \
--index-url https://gitlab.com/api/v4/projects/83894258/packages/pypi/simple
Requires Python ≥ 3.10 (CI tests 3.10 and 3.14). Versions are derived
from git tags (setuptools_scm) — no manual version bumps.
No Python at hand (Java/XSLT toolchains)? Use the Docker image published on every release:
docker run --rm -v "$PWD":/work \
registry.gitlab.com/glueswe/public/linkml:latest /work/schema.yaml -o /work/schema.xsd
Usage
CLI
Two entry points: gen-xsd (the linkml generator
convention, like gen-json-schema; see
docs/generators/xsd.md) and the richer linkml2xsd
group (convert / example / validate).
# linkml-style generator CLI
gen-xsd schema.yaml -o schema.xsd
gen-xsd schema.yaml --xsd-version 1.1 --schematron schema.sch
# Standard LinkML → XSD (targetNamespace derived from the schema id/default_prefix)
linkml2xsd convert schema.yaml -o schema.xsd
# eCH-0296 / Akoma Ntoso profile + a companion Schematron for rules
linkml2xsd convert schema.yaml -o schema.xsd --profile akn --schematron schema.sch
# Example XML instance / validate an instance against an XSD
linkml2xsd example schema.yaml -o example.xml
linkml2xsd validate example.xml --xsd schema.xsd
Python API
from linkml_to_xsd import XSDGenerator, SchematronGenerator, ConversionOptions
options = ConversionOptions(profile="akn", xsd_version="1.1", emit_appinfo=True)
xsd = XSDGenerator("schema.yaml", options=options).generate()
sch_gen = SchematronGenerator("schema.yaml", options=options)
sch = sch_gen.generate() if sch_gen.has_rules() else None
XSDGenerator accepts a file path, inline YAML, a dict, a SchemaDefinition or a
SchemaFrontend.
Options (ConversionOptions)
Every genuine mapping choice is a validated field with a default:
| Option | Default | Effect |
|---|---|---|
xsd_version |
"1.0" |
"1.1" also emits xs:assert for rules |
emit_schematron |
False |
(API flag; the CLI uses --schematron) |
inlining |
"linkml" |
or always_inline / always_reference |
reference_style |
"identifier" |
or uri (key/idref planned) |
emit_value_constraints |
True |
facets / @fixed |
emit_identity_constraints |
True |
xs:key/unique/keyref |
emit_documentation / emit_appinfo |
True / False |
annotations |
multilingual_documentation |
False |
split [en] … [de] …-tagged descriptions into per-language xs:documentation |
target_namespace |
None |
override the derived namespace |
profile |
None |
e.g. "akn" |
Architecture
src/linkml_to_xsd/
config.py # ConversionOptions — one toggle per mapping decision
frontend/ # SchemaFrontend over linkml-runtime SchemaView
emit/ # XSDGenerator (+ naming, typemap)
schematron/ # SchematronGenerator
rules.py # shared rule → XPath compiler (Schematron + xs:assert)
profile/ # base (no-op) + akn (eCH-0296 / Akoma Ntoso)
cli.py xml_generator.py
See docs/adr/ for architectural decisions (ADR 003 records the
move to SchemaView) and docs/LINKML_XSD_MAPPING.md
for the full LinkML ↔ XSD element mapping and current status.
Testing
Multi-tier and documented in tests/README.md;
docs/TEST_COVERAGE.md is the enforced feature × engine
matrix.
| Tier | Checks |
|---|---|
Compliance (tests/compliance/*) |
one feature per case → XSD compiles, matches its golden, accepts/rejects the right instances |
| Coverage | every case is feature-tagged; baseline features stay covered |
| Corpus | real kitchen_sink.yaml + meta.yaml convert and compile |
| Property (Hypothesis) | random supported schemas always compile |
| XSTS reference | inventories XSD constructs LinkML can never emit |
pytest
ruff check src tests && ruff format --check src tests
mypy src/linkml_to_xsd/
python tools/fetch_corpora.py [--xsts] # opt-in corpora (git-ignored)
python tools/gen_golden.py # refresh golden XSDs after a change
python tools/coverage_matrix.py # regenerate docs/TEST_COVERAGE.md
Contributing
See CONTRIBUTING.md — most improvements are data, not code: a new feature mapping is one compliance case + one option + one emitter change.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file linkml_xsd-0.2.0.tar.gz.
File metadata
- Download URL: linkml_xsd-0.2.0.tar.gz
- Upload date:
- Size: 98.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc13a6bc0b48c5f611e4f2e39a3e38bbcbe9a4b4abd08ca98b934fc50b731b9a
|
|
| MD5 |
67d1252bf0de7872b209e32a5ae97e05
|
|
| BLAKE2b-256 |
fa4babbbbea672abe793291b6c56d4cd4ba7cdd8c59681fa1a1e9173f2e09a39
|
File details
Details for the file linkml_xsd-0.2.0-py3-none-any.whl.
File metadata
- Download URL: linkml_xsd-0.2.0-py3-none-any.whl
- Upload date:
- Size: 45.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7ea316ea1813d2dc4aca29f63429ca0fa4b804bf42f9aea5b3a44c75e2a73a7
|
|
| MD5 |
371dbfa981adb756e758be46f36feae2
|
|
| BLAKE2b-256 |
a1ecfc41d2cb6fb42cd4587e2a4afe33c363845c20beb9c0a88e063dc1becd37
|