A SPARQL SELECT over urn:graph:catx-samm reconstructs the original SAMM JSON
payload via CONCAT aggregation. The result is asserted against the reference file
material_data_test_pa6gf30.json to confirm the CatX → RDF conversion
preserves all values without loss.
Node A loads two files into urn:graph:catx-samm: the YARRRML-converted
instance data (catx-samm.ttl) and the SAMM aspect model
(catx-samm-model.ttl). The round-trip query reads both to reconstruct every
section of the original CatX SAMM JSON — including the 547-entry PvT table — and verifies
that the reconstructed JSON is semantically identical to the source document.
material_data_test_pa6gf30.json (PA6GF30 material data,
5 top-level sections: materialInformation, mechanicalProperty, physicalProperty,
thermophysicalProperty, pvt).
Four correlated sub-SELECTs each aggregate a section into a JSON fragment, then the outer
SELECT concatenates them. The SAMM aspect model's RDF property list
(n3:properties/rdf:rest*/rdf:first) drives the general sections; thermophysical
scalars, linearThermalExpansionCoefficient, and pvt are handled by dedicated sub-SELECTs
because they require path traversal.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX n1: <urn:samm:io.catenax.material_data:1.0.0#> PREFIX n3: <urn:samm:org.eclipse.esmf.samm:meta-model:2.2.0#> SELECT (CONCAT( '{', ?sectionsJson, ',', '"thermophysicalProperty":{', ?thermoScalarsJson, ',"linearThermalExpansionCoefficient":{', ?ltecJson, '}}', ',', '"pvt":', ?pvtJson, '}' ) AS ?json) FROM <urn:graph:catx-samm> WHERE { # pvt — 547 entries, each a {temperature, specificVolume, pressure} object { SELECT ?mat (CONCAT('[', GROUP_CONCAT(?pvtEntry ; SEPARATOR=','), ']') AS ?pvtJson) WHERE { { SELECT ?mat ?pvt (CONCAT('{', GROUP_CONCAT( CONCAT('"', STRAFTER(STR(?p), '#'), '":', IF(REGEX(STR(?v), '^-?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'), STR(?v), CONCAT('"', STR(?v), '"'))) ; SEPARATOR=',') , '}') AS ?pvtEntry) WHERE { ?mat a n1:MaterialData . ?mat n1:thermophysicalProperty/n1:pvt ?pvt . ?pvt ?p ?v . FILTER(isLiteral(?v) && ?p != rdf:type) } GROUP BY ?mat ?pvt } } GROUP BY ?mat } # linearThermalExpansionCoefficient scalars { SELECT ?mat (GROUP_CONCAT( CONCAT('"', STRAFTER(STR(?p), '#'), '":', IF(REGEX(STR(?v), '^-?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'), STR(?v), CONCAT('"', STR(?v), '"'))) ; SEPARATOR=',') AS ?ltecJson) WHERE { ?mat a n1:MaterialData . ?mat n1:thermophysicalProperty/n1:linearThermalExpansionCoefficient ?ltec . ?ltec ?p ?v . FILTER(isLiteral(?v) && ?p != rdf:type) } GROUP BY ?mat } # thermophysicalProperty scalars (humidity, meltingTemperature, glassTransitionTemperature, waterAbsorption) { SELECT ?mat (GROUP_CONCAT( CONCAT('"', STRAFTER(STR(?p), '#'), '":', IF(REGEX(STR(?v), '^-?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'), STR(?v), CONCAT('"', STR(?v), '"'))) ; SEPARATOR=',') AS ?thermoScalarsJson) WHERE { ?mat a n1:MaterialData . ?mat n1:thermophysicalProperty ?thermo . ?thermo ?p ?v . FILTER(isLiteral(?v) && ?p != rdf:type) } GROUP BY ?mat } # General sections via SAMM aspect model properties list # (materialInformation, mechanicalProperty, physicalProperty) { SELECT ?mat (GROUP_CONCAT(?sectionJson ; SEPARATOR=',') AS ?sectionsJson) WHERE { { SELECT ?mat ?sectionName (CONCAT('"', ?sectionName, '"":{"', GROUP_CONCAT( CONCAT('"', STRAFTER(STR(?p), '#'), '":', IF(REGEX(STR(?v), '^-?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'), STR(?v), CONCAT('"', STR(?v), '"'))) ; SEPARATOR=','), '}') AS ?sectionJson) WHERE { ?mat a n1:MaterialData . n1:MaterialData n3:properties/rdf:rest*/rdf:first ?sectionProp . BIND(STRAFTER(STR(?sectionProp), '#') AS ?sectionName) FILTER(?sectionName != 'thermophysicalProperty') ?mat ?sectionProp ?sectionInst . ?sectionInst ?p ?v . FILTER(isLiteral(?v) && ?p != rdf:type) } GROUP BY ?mat ?sectionName } } GROUP BY ?mat } }
A single row with binding ?json containing a JSON object whose top-level keys
match the original payload. Object key order depends on GROUP_CONCAT evaluation
order (non-deterministic in SPARQL); the assertion uses canonical comparison (keys sorted
recursively, array-of-objects sorted by serialisation) so order differences do not cause
false failures.
| Section | Key | Value |
|---|---|---|
| materialInformation | materialName | PA6GF30 |
| materialInformation | materialIdentifier | Z1234 |
| mechanicalProperty | youngsModulus | 9800 |
| mechanicalProperty | impactStrength | 74 |
| mechanicalProperty | stressAtBreak | 140 |
| mechanicalProperty | flexuralStrength | 210 |
| mechanicalProperty | flexuralModulus | 8600 |
| mechanicalProperty | strainAtBreak | 3 |
| physicalProperty | density | 1530 |
| thermophysicalProperty | humidity | 2.1 |
| thermophysicalProperty | meltingTemperature | 223 |
| thermophysicalProperty | glassTransitionTemperature | 20 |
| thermophysicalProperty | waterAbsorption | 6.5 |
| thermophysicalProperty → linearThermalExpansionCoefficient | Parallel | 0.0025 |
| thermophysicalProperty → linearThermalExpansionCoefficient | Transverse | 0.0115 |
| pvt | (547 entries) | temperature, specificVolume, pressure |