How two SPARQL INSERTs bridge Catena-X SAMM RDF and Manufacturing-X AAS-ontology RDF into a shared PMDCO graph pattern into the same PMDCO graph pattern — and why that makes a schema-free cross-dataspace query possible.
After each dataspace pipeline loads its raw source data, the triplestore holds two structurally alien graphs:
urn:graph:catx-samm — SAMM aspect RDF, where properties are identified by
Catena-X-specific IRIs such as mat:stressAtBreak and units use the SAMM unit
vocabulary (urn:samm:…:megapascal). The staging graph also contains the
SAMM aspect model (catx-samm-model.ttl), which declares each
samm:Property, its samm:characteristic, and the
samm-c:unit the INSERT reads to identify units and labels.urn:graph:mfgx-aas — AAS-ontology RDF produced by py-aas-rdf, where properties
are aas:Property individuals identified indirectly through a
semanticId → keys → value chain pointing to IDTA IRI strings such as
https://admin-shell.io/idta/…/TensileStrengthMean/1/0.Neither graph knows about the other's vocabulary. A SPARQL query over both would need separate path patterns for every property — or a UNION for every dataspace. The PMDCO Transform eliminates that by writing both into the same structural pattern before any query runs.
Every property from either source — whether it came in as a SAMM field name or an AAS
semanticId string — is written into the target graph as the same four-node chain:
# material entity (BFO material entity) ex:316-4401_material a pmd:PMD_0000000, obo:BFO_0000040 ; rdfs:label "Steel 316/4401" ; obo:RO_0000086 ex:316-4401_tensile_strength . # has quality # quality individual — class IRI from TTO or PMDCO ex:316-4401_tensile_strength a tto:TTO_0000053 ; # tensile strength obo:RO_0000052 ex:316-4401_material ; # characteristic of obo:IAO_0000417 ex:316-4401_tensile_strength_svs . # is quality measured as datum # OBI scalar value specification ex:316-4401_tensile_strength_svs a obo:OBI_0001931 ; obo:OBI_0001938 ex:316-4401_tensile_strength_value . # has value specification # QUDT QuantityValue — same predicate chain as CatX output ex:316-4401_tensile_strength_value a qudt:QuantityValue ; qudt:unit unit:MegaPA ; qudt:numericValue "632" .
The Catena-X INSERT produces exactly the same four-node chain for PA6GF30 in
urn:graph:catx. Both pipelines converge on qudt:numericValue —
the single predicate the cross-dataspace SELECT actually reads.
Each INSERT uses VALUES tables to declare the schema-specific identity of each
property and its PMDCO class. CATX_INSERT reads urn:graph:catx-samm
(SAMM instance data + aspect model) and writes to urn:graph:catx.
AAS2KG_INSERT reads urn:graph:mfgx-aas and writes to
urn:graph:mfgx. Both produce the same PMDCO predicate chain.
For the Catena-X path the property is identified directly by its SAMM IRI:
# CatX path: match by SAMM property IRI (unit: = https://qudt.org/vocab/unit/) VALUES (?prop ?qualityClass ?qdtUnit) { ( mat:stressAtBreak pmd:PMD_0000952 unit:MegaPA ) # tensile strength ( mat:youngsModulus pmd:PMD_0000618 unit:MegaPA ) # elastic modulus ( mat:impactStrength pmd:PMD_0000518 unit:J-PER-M2 ) # impact strength ( mat:meltingTemperature pmd:PMD_0000851 unit:DEG_C ) # melting point }
For the Manufacturing-X path the property has no direct IRI — it is encoded as a
string value inside an aas:Key node reachable via a three-hop chain
(aas:Property → semanticId → keys → value). The INSERT navigates that chain and
maps the string to the same TTO/PMDCO quality class:
# MfgX path: navigate semanticId chain, match by IRI string GRAPH <urn:graph:mfgx-aas> { OPTIONAL { ?tensileP a aas:Property ; aasP:value ?tensileValue ; aasSM:semanticId ?tss . ?tss aasR:keys ?tk . ?tk aasK:value "https://admin-shell.io/idta/InspectionDocumentsOfSteelProducts/TensileStrengthMean/1/0" . } }
Both paths write a tto:TTO_0000053 (tensile strength) into the target graph.
The query never sees the source vocabulary — it only ever reads the shared PMDCO/TTO class IRI.
SPARQL alone can match class IRIs in VALUES bindings without the ontologies being
present — so the INSERT technically executes without them. But the ontologies earn their keep
in three ways:
tto:TTO_0000053 rdfs:label "tensile strength" exists in the TTO ontology file.
If TTO is loaded into the triplestore, any downstream query can fetch labels via
?qualityClass rdfs:label ?label instead of hard-coding string mappings.
In this demo the label annotation INSERT in Node C substitutes for that, but in a production
endpoint with loaded ontologies, no annotation step is needed.rdfs:subClassOf chains (e.g. tensile strength is a
mechanical property is a material quality). A SPARQL endpoint with RDFS inference enabled can
then answer queries like "give me all mechanical properties" without listing every leaf class
in a VALUES block.VALUES tables in the INSERT and the label annotation INSERT in the PMDCO
Transform step replicate what a loaded ontology would provide automatically in a production
deployment.
Because the INSERT wrote the same predicate chain into both urn:graph:catx
and urn:graph:mfgx, the cross-dataspace SELECT can traverse both graphs with
one path expression. SPARQL evaluates the path over all named graphs simultaneously — it finds
the same pattern in both and returns results from both without any dataspace-specific branch.
# This one path works for both dataspaces ?component obo:BFO_0000051 ?mat . # hasPart → material ?mat obo:RO_0000086 ?quality . # has quality ?quality a ?qualityType . ?quality obo:IAO_0000417 ?datum . # is measured as ?datum obo:OBI_0001938 ?qv . # has value specification ?qv qudt:numericValue ?value . # ← same predicate for both PA6GF30 and Steel 316
If the INSERT had not run — or had produced different predicate chains for the two dataspaces —
the query would need a UNION branch for each source vocabulary, and would need
to be rewritten every time a new dataspace joins. With the shared PMDCO pattern in place,
adding a third dataspace means writing one new INSERT, not touching the query.