digitalbazaar/json-ld — Issue #10: Allow frames to say:  "predicate p always points to a set"
Author: jmandel
Created: 2011-12-01 21:59:03+00:00
State: open

This issue is about making it easier for frames to specify that certain predicates should always be represented as JSON arrays (sets) wherever they occur. One approach is to allow explicit `@structure` directives to augment a frame's context, such as:

"@context": {
"vcard:tel": {
"@iri": "http://www.w3.org/2006/vcard/ns#tel",
@structure": "@set"
}
}

Why is this important? Let's say we're working with data where a certain predicate is allowed to take mutiple objects. For instance, with the vCard RDF ontology, the `v:tel` predicate can point to multiple telephone number objects:

{
"@context": {
"foaf": "http://xmlns.com/foaf/0.1/",
"sp": "http://smartplatforms.org/terms#",
"vcard": "http://www.w3.org/2006/vcard/ns#"
},
"@subject": "http://localhost:7000/records/00001/demographics",
"@type": "sp:Demographics",
"foaf:gender": "male",

"vcard:tel": [{
"@type": [
"vcard:Pref",
"vcard:Tel",
"vcard:Cell"
],
"rdf:value": "800-888-8888"
}, {
"@type": [
"vcard:Tel",
"vcard:Home"
],
"rdf:value": "800-777-7777"
}]
}

What happens when there's only *one* telpehone number? It depends on how the data are framed. If a frame doesn't force consistency, we have to make up for it by adding complexity to app logic:

if (patientRecord["v:tel"].constructor == Array) {
processPhoneNumbers( patientRecord["v:tel"] );
} else {
processPhoneNumbers( [patientRecord["v:tel"]] );
}

Yuck! So we'd better get the frame right, with something like:

[{
"@context": {
"foaf": "http://xmlns.com/foaf/0.1/",
"sp": "http://smartplatforms.org/terms#",
"vcard": "http://www.w3.org/2006/vcard/ns#"
},

"@type": "sp:Demographics",
"vcard:tel": []
}]

So far, so good. But what if `vcard:tel` is used in more than one position in the hierarchy? The frame has to explicitly reflect this everywhere the predicate might appear, e.g.:

[{
"@context": {
"foaf": "http://xmlns.com/foaf/0.1/",
"sp": "http://smartplatforms.org/terms#",
"vcard": "http://www.w3.org/2006/vcard/ns#"
},

"@type": "sp:Demographics",
"vcard:tel": [],
"sp:emergencyContact": {
"vcard:tel": []
},
"sp:insuranceProvider": {
"vcard:tel": []
},
"sp:primaryCareDoctor": {
"vcard:tel": []
},
"sp:caseManager": {
"vcard:tel": []
}
}]

This gets verbose! And all I really want to say is "anytime `vcard:tel` appears, the object should be a JSON array."

One proposal for this was an additional field `@structure` directive in the context of the frame, allowing the body of the frame to stay shallow. My frame could then be as simple as:

[{
"@context": {
"foaf": "http://xmlns.com/foaf/0.1/",
"sp": "http://smartplatforms.org/terms#",
"vcard": "http://www.w3.org/2006/vcard/ns#",
"vcard:tel": {"@structure": "@set"}
},

"@type": "sp:Demographics"
}]