Repository navigation
Mapping-set selection can bridge document shapes via @nest, and the spec should say so #135
Description
Selection can bridge document shapes, not only vocabularies, because a promoted fragment may carry @nest. The selection rule already permits it: a processor writes { "@id": <synonym IRI>, ...fragment without x-oold-sssom }, and @nest is a member of a term definition. Nothing in the spec says so, and the surrounding prose reads as though a mapping set only renames terms.
This extends the normalization-by-chaining idea in #11 (expand, flatten) with the two pieces that turn it into a shape conversion: @nest in a promoted fragment, and framing before selection. It is a mapping-selection requirement in the sense of #108, and it depends on schema-derived frames as in #91.
Everything below is verified with pyld; both schemas pass the validator at v1.0.0-rc.2 (15/15 checks).
The pair
The flat shape, where the number sits on the quantity:
{
"$schema": "https://oo-ld.org/latest/meta/oold-meta-schema.json",
"$id": "QuantityValue.schema.json",
"title": "QuantityValue",
"description": "A number with a unit. The flat shape: the number sits on the quantity itself.",
"@context": {
"qudt": "http://qudt.org/schema/qudt/",
"qunit": "http://qudt.org/vocab/unit/",
"type": {"@id": "@type", "@container": "@set"},
"value": "qudt:value",
"unit": {"@id": "qudt:hasUnit", "@type": "@vocab"},
"QuantityValue": "qudt:QuantityValue"
},
"type": "object",
"properties": {
"type": {"type": "array", "items": {"type": "string"}, "default": ["QuantityValue"]},
"value": {"type": "number"},
"unit": {"type": "string", "format": "iri-reference"}
},
"required": ["value"],
"examples": [{"type": ["QuantityValue"], "value": 12.7, "unit": "qunit:SEC"}]
}The same quantity in the shape EMMO uses, where the number is a node. Its QUDT reading is declared here, in the schema that wants the import, so the flat schema is untouched:
{
"$schema": "https://oo-ld.org/latest/meta/oold-meta-schema.json",
"$id": "NestedQuantityValue.schema.json",
"title": "NestedQuantityValue",
"description": "The same quantity in the shape EMMO uses: the number is a node reached from the quantity.",
"@context": {
"emmo": "https://w3id.org/emmo#",
"qudt": "http://qudt.org/schema/qudt/",
"type": {
"@id": "@type",
"@container": "@set"
},
"value": "emmo:hasQuantityValuePart",
"numerical": "emmo:hasNumericalValue",
"unit": {
"@id": "emmo:hasMeasurementUnit",
"@type": "@vocab"
},
"NestedQuantityValue": "emmo:QuantityValue",
"qunit": "http://qudt.org/vocab/unit/"
},
"x-oold-context": {
"value": {
"@nest": {
"x-oold-sssom": {
"predicate_id": "skos:relatedMatch",
"mapping_set_id": "https://w3id.org/oo-ld/schemas/mappings/qudt.sssom.tsv",
"comment": "grouping only: under the QUDT reading the nesting carries no meaning"
}
}
},
"numerical": {
"qudt:value": {
"@nest": "value",
"x-oold-sssom": {
"predicate_id": "skos:exactMatch",
"mapping_set_id": "https://w3id.org/oo-ld/schemas/mappings/qudt.sssom.tsv",
"comment": "QUDT puts the number on the quantity; the nesting is dropped on export"
}
}
}
},
"type": "object",
"properties": {
"type": {
"type": "array",
"items": {
"type": "string"
},
"default": [
"NestedQuantityValue"
]
},
"value": {
"type": "object",
"properties": {
"numerical": {
"type": "number"
}
},
"required": [
"numerical"
]
},
"unit": {
"type": "string",
"format": "iri-reference"
}
},
"required": [
"value"
],
"examples": [
{
"type": [
"NestedQuantityValue"
],
"value": {
"numerical": 12.7
},
"unit": "qunit:SEC"
}
]
}Note the two synonyms: value maps to @nest, so under the QUDT reading the JSON nesting carries no meaning at all, and numerical maps to qudt:value while staying nested under value in the document.
What each reading produces
A. the nested instance under its own context
<https://example.org/m1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/emmo#QuantityValue> .
<https://example.org/m1> <https://w3id.org/emmo#hasMeasurementUnit> <http://qudt.org/vocab/unit/SEC> .
<https://example.org/m1> <https://w3id.org/emmo#hasQuantityValuePart> _:b0 .
_:b0 <https://w3id.org/emmo#hasNumericalValue> "1.27E1"^^<http://www.w3.org/2001/XMLSchema#double> .
B. the same instance with the qudt set selected
<https://example.org/m1> <http://qudt.org/schema/qudt/value> "1.27E1"^^<http://www.w3.org/2001/XMLSchema#double> .
<https://example.org/m1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/emmo#QuantityValue> .
<https://example.org/m1> <https://w3id.org/emmo#hasMeasurementUnit> <http://qudt.org/vocab/unit/SEC> .
C. flat data imported: compacted with the promoted context
{"@id": "https://example.org/m1", "type": ["qudt:QuantityValue"], "qudt:hasUnit": {"@id": "qunit:SEC"}, "value": {"numerical": 12.7}}
D. arriving nested RDF: compaction alone does not restore the shape
{"@graph": [{"@id": "_:b0", "numerical": 12.7}, {"@id": "https://example.org/m1", "type": ["NestedQuantityValue"], "unit": "qunit:SEC", "value": {"@id": "_:b0"}}]}
E. framing with the schema restores it, and the set then reads it flat
framed: {"@id": "https://example.org/m1", "type": ["NestedQuantityValue"], "unit": "qunit:SEC", "value": {"numerical": 12.7}}
<https://example.org/m1> <http://qudt.org/schema/qudt/value> "1.27E1"^^<http://www.w3.org/2001/XMLSchema#double> .
<https://example.org/m1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/emmo#QuantityValue> .
<https://example.org/m1> <https://w3id.org/emmo#hasMeasurementUnit> <http://qudt.org/vocab/unit/SEC> .
F. the reverse as a context operation is rejected
JsonLdError ('JSON-LD compact error; nested property must have an @nest value resolving to @nest.',)
Type: jsonld.SyntaxError
Code:
What this says
- A mapping set can decide the graph shape a document produces. A and B are the same file: an EMMO graph with a node, or a flat QUDT graph, chosen by selection. The type and unit keep their EMMO terms in B, since only
valueandnumericalcarry QUDT synonyms, which is the ordinary fallback behaviour. - The importer declares the import. The
@nestfragments live in the nested schema. C shows flat data compacting into the nested document that schema expects, without the flat schema knowing anything about it. - A graph cannot be reshaped by a context. F is rejected with
invalid @nest value:@nestmay only point at a term that is itself@nest. That is correct, because dropping an intermediate node and reattaching its literal asserts something the graph does not contain. - So arriving RDF is framed first. D shows compaction alone returning a flat list of node objects; E shows framing restoring the document, after which selection reads it either way. The frame follows from the schema, so this is a build step rather than a judgement, which is where Bundle the validation scripts as a reusable package (and/or fold into oold-python) #91 comes in.
Suggested spec additions
- In Selection, state that a promoted fragment may carry
@nest, with a two-line example. The rule already allows it; only the prose is missing. - State the boundary as a property rather than a limitation: a mapping set decides which graph a document produces; it cannot reshape a graph. Cite the
invalid @nest valuerule as the reason. - Note that a conforming pipeline frames arriving RDF with the schema's frame before selection, so shape conversion is framing plus selection rather than a rule engine.
Filed from the reference-schema work, where the flat and nested quantity value is the standing example of two communities disagreeing about structure rather than about names.
Activity