SKOS Explorer and Validator
SKOS stands for Simple Knowledge Organization System, the W3C standard for describing vocabularies. Paste or upload a SKOS vocabulary — a thesaurus, taxonomy, classification or subject-heading list published as RDF. It is shown as a tree, every SKOS term it uses is explained in plain words, and it is checked against the rules of the W3C SKOS Reference. New to SKOS? The glossary below explains the whole vocabulary without any file.
Two versions of one vocabulary? Compare them with the Vocabulary Diff. Rules of your own? Check them with the SHACL Validator. For automation there is an OpenAPI description of the API.
📖 SKOS in plain words: every class and property
SKOS (Simple Knowledge Organization System) is the W3C standard for publishing thesauri, taxonomies, classification schemes and subject-heading lists so that software can read them. A vocabulary is a set of concepts; each concept has labels in one or more languages and links to other concepts. That is nearly all of it — the terms are:
skos:Concept class | An idea or notion — a unit of thought. The thing a vocabulary is made of: one subject heading, one category, one thesaurus entry. |
skos:ConceptScheme class | A set of concepts that belong together: one thesaurus, one classification, one taxonomy. |
skos:inScheme property | Says which concept scheme a concept belongs to. A concept may be in several, or in none. |
skos:hasTopConcept property | Points from a concept scheme to a concept at the top of its hierarchy — an entry point for browsing. |
skos:topConceptOf property | The reverse of hasTopConcept: this concept is a top-level entry of that scheme. It also means the concept is in the scheme. |
skos:prefLabel property | The preferred name of a concept. At most one per language. |
skos:altLabel property | Another name for the same concept: a synonym, an abbreviation, an older term. Used to lead searchers to the concept. |
skos:hiddenLabel property | A name that should be findable by search but never displayed — typically a common misspelling. |
skos:notation property | A code that identifies the concept inside its scheme, such as a classification number (“641.5”). Not a word in any language. |
skos:note property | A general note about the concept. The other note properties below are more specific kinds of it. |
skos:definition property | A complete explanation of what the concept means. |
skos:scopeNote property | Says what the concept does and does not cover, to guide whoever assigns it. |
skos:example property | An example of the concept in use. |
skos:historyNote property | Describes how the meaning or form of the concept changed over time. |
skos:editorialNote property | A note for the people maintaining the vocabulary, such as work still to be done. |
skos:changeNote property | Records a specific change made to the concept, for administration. |
skos:semanticRelation property | The parent of all links between two concepts. Normally one of its specific kinds is used instead. |
skos:broader property | Points to a more general concept (“cats” broader “mammals”). Direct parent only; SKOS does not treat it as transitive. |
skos:narrower property | Points to a more specific concept. The reverse of broader: if A is broader than B, then B is narrower than A. |
skos:related property | Links two concepts that are associated but neither is more general than the other (“cats” related “cat food”). Works in both directions. |
skos:broaderTransitive property | Any ancestor, not just the direct parent. Normally worked out by software from broader, not written by hand. |
skos:narrowerTransitive property | Any descendant, not just a direct child. Normally worked out by software from narrower, not written by hand. |
skos:Collection class | A labelled group of concepts, such as “milk by source animal”. A grouping device, not a concept itself. |
skos:OrderedCollection class | A collection whose members have a meaningful order. |
skos:member property | Says that a concept (or another collection) belongs to a collection. |
skos:memberList property | The members of an ordered collection, in order. |
skos:mappingRelation property | The parent of all links between concepts in different schemes. Normally one of its specific kinds is used. |
skos:exactMatch property | The two concepts, from different schemes, mean the same and can be used interchangeably in a wide range of applications. Transitive. |
skos:closeMatch property | The two concepts are similar enough to be interchangeable in some applications. Weaker than exactMatch and not transitive. |
skos:broadMatch property | A concept in another scheme that is more general than this one. |
skos:narrowMatch property | A concept in another scheme that is more specific than this one. |
skos:relatedMatch property | A concept in another scheme that is associated with this one, without being broader or narrower. |
skosxl:Label class | A label treated as a thing of its own, so that more can be said about it (who coined it, how it relates to other labels). |
skosxl:literalForm property | The text of an XL label. Exactly one per label. |
skosxl:prefLabel property | Attaches an XL label as the preferred name; it implies an ordinary skos:prefLabel with the same text. |
skosxl:altLabel property | Attaches an XL label as an alternative name. |
skosxl:hiddenLabel property | Attaches an XL label as a hidden name. |
skosxl:labelRelation property | A link between two XL labels, for example an acronym and its expansion. |
ℹ️ What is checked, and what are the limits?
Violations: the six integrity conditions
The SKOS Reference states six conditions formally. A vocabulary that breaks one is not consistent with the SKOS data model. These are the only findings called violations here.
- S14 — More than one preferred label in the same language. A resource has no more than one skos:prefLabel per language tag. With two, software cannot know which name to show.
- S13 — The same label used as two kinds of label. skos:prefLabel, skos:altLabel and skos:hiddenLabel are pairwise disjoint: one text in one language can be only one of them for a given concept.
- S27 — Concepts both related and in the same hierarchy branch. skos:related is disjoint with skos:broaderTransitive: if one concept is an ancestor of the other, they cannot also be merely “related”.
- S46 — Exact match that is also a broader, narrower or related match. skos:exactMatch is disjoint with skos:broadMatch and skos:relatedMatch: two concepts cannot mean the same and also be more general or merely associated.
- S9 — A resource that is both a concept and a concept scheme. skos:ConceptScheme is disjoint with skos:Concept. Using a relation such as skos:broader on a scheme makes it a concept by implication.
- S37 — A collection that is also a concept or a concept scheme. skos:Collection is disjoint with skos:Concept and skos:ConceptScheme. A collection groups concepts; it cannot take part in broader, narrower or related links itself.
The checks apply what the Reference says follows from the data: skos:narrower is the reverse of skos:broader, skos:related works in both directions, skos:exactMatch is transitive, a SKOS-XL label implies the plain label, and anything used in a relation between concepts is a concept.
Warnings
Allowed by SKOS, but nearly always a mistake.
- Terms that are not part of SKOS. These use the SKOS namespace but the Reference defines no such term — usually a typing mistake or a term from the 2004 draft. Software will silently ignore them.
- The hierarchy loops back on itself. Following skos:broader from a concept leads back to the same concept. SKOS does not forbid it, but no tree can be drawn and most tools break.
- A concept linked to itself. A concept is its own broader, narrower or related concept.
- Concepts without a preferred label. SKOS allows it, but a concept with no skos:prefLabel has no name to display.
- Top concepts that have a broader concept. By convention a top concept is at the top of the hierarchy of its scheme, so it should have no broader concept in that scheme.
Notes
- Concepts that belong to no concept scheme. The file defines concept schemes, but these concepts have neither skos:inScheme nor skos:topConceptOf.
- Top-level concepts not declared as top concepts. These concepts are in a scheme and have no broader concept, but the scheme does not list them with skos:hasTopConcept, so a tool that starts browsing from the top concepts will miss them.
- Different concepts with the same preferred label. Allowed, but two concepts in one scheme sharing a preferred label in one language are hard to tell apart.
- Labels without a language tag. The label does not say which language it is in, so it cannot be chosen by language and the one-per-language rule cannot protect it.
- Links to concepts the file says nothing about. A broader, narrower or related link points to a resource that has no statements of its own in this file. It may live in another file.
What this doesn't do
- It doesn't judge the content. Whether “cats” really belongs under “mammals” is for a person to decide.
- It never fetches anything. Links to other vocabularies are shown, not followed, and a JSON-LD file whose
@context is a web address is refused — put the context inline.
- No OWL reasoning beyond the SKOS rules listed above.
Limits and privacy
- 1024 KB and 60,000 statements per vocabulary, 60 per hour per address (the page and the API are counted separately). Very large trees are drawn only in part; the checks always cover everything.
- The vocabulary is read in memory for the one request. It is not stored and not logged.
💡 Show API usage examples (cURL, JavaScript, Python)
No API key. One vocabulary per request, up to 1024 KB.
cURL
curl -sS -X POST https://devops.majbase.com/skos-explorer/api -F "file=@vocabulary.ttl"
# just the verdict and the problems
curl -sS -X POST https://devops.majbase.com/skos-explorer/api -F "file=@vocabulary.ttl" -F "lang=en" \
| jq '{verdict, issue_totals, issues: [.issues[] | {severity, rule, title, count}]}'
JavaScript
const res = await fetch("https://devops.majbase.com/skos-explorer/api", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: turtleText, format: "turtle", lang: "en" }),
});
const report = await res.json();
console.log(report.verdict, report.summary.concepts, report.issues);
Python
import requests
with open("vocabulary.ttl", "rb") as f:
report = requests.post("https://devops.majbase.com/skos-explorer/api", files={"file": f}, timeout=60).json()
print(report["verdict"], report["issue_totals"])
Response fields
verdict: violations, warnings, clean or no_skos; issue_totals counts findings by severity.
issues: one entry per kind of finding with code, severity (violation, warning, info), rule (the condition number in the Reference, for violations), title, explain, count and up to 10 examples.
summary, languages, trees (the hierarchy per concept scheme), concepts (labels, notes, links and its own issues, by URI; tree nodes carry severity for their own worst finding and below for the worst one further down), collections, terms_used (each SKOS term found, with its meaning).
validator_version: the version of this tool that produced the report; processing_time_ms: how long reading and checking took.
- Errors come back as
{"error": "…"} with status 400 (unreadable or too large) or 429 (rate limit).