In this informative note we offer advice to OSLC Technical Committees on modeling links and relationships between OSLC resources.
This is a Non-Standards Track Work Product. The patent provisions of the OASIS IPR Policy do not apply.
This document was last revised or approved by the Project Governing Board of the OASIS Open Services for Lifecycle Integration (OSLC) Open Project on the above date. The level of approval is also listed above. Check the “Latest stage” location noted above for possible later revisions of this document. Any other numbered Versions and other technical work produced by the Open Project are listed at https://open-services.net/about/.
Comments on this work can be provided by opening issues in the project repository or by sending email to the project’s public comment list oslc-op@lists.oasis-open-projects.org.
[OSLC-Link-v1.0]
OSLC Core Version 3.0: Link Guidance Version 1.0.
Edited by Jim Amsden.
16 December 2021.
OASIS Project Note 01.
https://docs.oasis-open-projects.org/oslc-op/oslc-link-guidance/v1.0/pn01/oslc-link-guidance.html.
Latest stage: https://docs.oasis-open-projects.org/oslc-op/oslc-link-guidance/v1.0/oslc-link-guidance.html.
Copyright © OASIS Open 2021. All Rights Reserved.
All capitalized terms in the following text have the meanings assigned to them in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The full Policy may be found at the OASIS website.
This specification is published under the Attribution 4.0 International (CC BY 4.0). Portions of this specification are also provided under the Apache License 2.0.
All contributions made to this project have been made under the OASIS Contributor License Agreement (CLA).
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this section are included on all such copies and derivative works. However, this document itself may not be modified in any way, including by removing the copyright notice or references to OASIS, except as needed for the purpose of developing any document or deliverable produced by an OASIS Open Project or OASIS Technical Committee (in which case the rules applicable to copyrights, as set forth in the OASIS IPR Policy, must be followed) or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
The name "OASIS" is a trademark of OASIS, the owner and developer of this specification, and should be used only to refer to the organization and its official outputs. OASIS welcomes reference to, and implementation and use of, specifications, while reserving the right to enforce its marks against misleading uses. Please see https://www.oasis-open.org/policies-guidelines/trademark for above guidance.
The Core workgroup's guidance to OSLC domain workgroups is that relationships are uni-directional and in most cases relationships should be modeled as links. We offer two ways to express relationships, a link and an anchor. Let's define those terms and others that we will use in this document:
This section is non-normative.
The RDF data model gives us a number of value-types to express relationships, some more complex than others. We expect that the majority of links will be expressed with the most simple option, URI Reference or as it is known in conversation, a Link. In this simple case, a Link refers to a RDF assertion where the predicate is the URI. It is the subject, predicate, object that represents the relationship. For more complex cases, when a relationship must be annotated with property-values, we use what is called an Anchor, which is a link plus information that annotates or labels that link. Read the sub-sections below for details and examples of Links and Anchors.
Use this when you need a simple link and you do not need to annotate the link with property values. Most relationships should be represented this way.
In RDF terminology, a link is called a URI Reference. In OSLC resource constraints, you express a link as a property with OSLC valueType of Resource as described in [OSLCCore3]. The following example shows a property terms:subscribesTo
that you might find inside a customer resource that links to a resource that is "subscribedTo" by the customer.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> </rdf:RDF>
oscl:valueType oslc:Resource
as shown in the example below.
<#dcterms-title> a oslc:Property ; oslc:name "subscribesTo" ; oslc:occurs oslc:Zero-or-many ; oslc:propertyDefinition terms:subscribesTo ; oslc:valueType oslc:Resource.
Relationships in OSLC resources are at their simplest an RDF property whose object is a URI. In some cases within one system, it is necessary to require a closed link, i.e. require the object of a link be of one or more specific resource types. In general, it is better to be open like the web and not place restrictions on the type of resource linked to. The property's purpose and name should clearly reflect the scenarios it is supporting. Since the usage of these relationship properties may exist for a long period of time, specification authors should use great care in determining these.
As resources evolve over time, and they adapt to different situations, different types will be exposed as targets to existing link types. Well behaved clients should gracefully handle resource types they don't expect when exercising links in resources. Specifications should allow links to be open ended (have any type, specifying Range any), and use text in the property description to suggest expected types, without being limiting. For example: “Change request affects a plan item. It is likely that the target resource will be an oslc_cm:ChangeRequest but that is not necessarily the case.” Some implementations may only work well if the link object comes from a set of “known” or “expected” types. The following graceful degradation sequence is suggested for providers when an unexpected type is encountered:
By "place" we mean the resource that contains the link assertion. In most cases, link information should be captured in one place to avoid information redundancy and the associated information maintenance issues.
There are two general sources of information redundancy:
Duplicated triples have the same problem as any redundancy, and should be avoided whenever possible. This redundancy may be required to provide the information independently from different servers, but it must be handled with care to avoid data integrity issues.
There are times when duplicate triples are necessary, and there is a preferred way to use them. For example, a request to GET resource A might respond with triple "A ex:affects B", and a request to GET resource B might also respond with the same "A ex:affects B" triple. If they are on different servers then B's assertion might get out of date. Clients may judge the authority of any RDF statement based on its origin or provenance.Storing the link in one place simplifies updates.
Relationships are expressed as RDF triples and triples do not have property values - only resources have property values. Links are used to express relationships. Many relationships can be represented by a single link, but some relationships need to be annotated with property values. For example, if I am trying to represent the subscriber relationship between a customer and a magazine, I may need to record an expiration date for the relationship. One way to do this is to use an RDF concept known as reification. Reification is a way to make a statement about a statement. See RDF Syntax Specification: Reifying Statements for more information on this concept (reference: RDF Syntax).
Assuming the subscriber scenario, the example below shows how you would use reification to express the annotation.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:resource="http://example.com/magazines/Cat_Fancy" /> </terms:Customer> <rdf:Statement rdf:about="#n1"> <terms:expirationDate>2010-06-03</terms:expirationDate> <terms:annualPriceUSD>23.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> <rdf:subject rdf:resource="http://example.com/customers/4321"/> <rdf:object rdf:resource="http://example.com/magazines/Field_and_Stream"/> <rdf:predicate rdf:resource="http://example.com/terms/subscribesTo" /> </rdf:Statement> <rdf:Statement rdf:about="#n2"> <terms:expirationDate>2010-01-22</terms:expirationDate> <terms:annualPriceUSD>15.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/mail" /> <rdf:subject rdf:resource="http://example.com/customers/4321"/> <rdf:object rdf:resource="http://example.com/magazines/Cat_Fancy"/> <rdf:predicate rdf:resource="http://example.com/terms/subscribesTo" /> </rdf:Statement> </rdf:RDF>
However, there is a better RDF/XML form, made possible by the rdf:ID attribute. OSLC implementations should prefer this next form because it is easier to read and easier to parse.
<rdf:RDF xmlns:terms="http://example.com/terms/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:ID="n1" rdf:resource="http://example.com/magazines/Field_and_Stream" /> </terms:Customer> <terms:Customer rdf:about="http://example.com/customers/4321"> <terms:subscribesTo rdf:ID="n2" rdf:resource="http://example.com/magazines/Cat_Fancy" /> </terms:Customer> <rdf:Description rdf:about="#n1"> <terms:expirationDate>2010-06-03</terms:expirationDate> <terms:annualPriceUSD>23.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> </rdf:Description> <rdf:Description rdf:about="#n2"> <terms:expirationDate>2010-01-22</terms:expirationDate> <terms:annualPriceUSD>15.95</terms:annualPriceUSD> <terms:delivery rdf:resource="http://example.com/terms/online" /> </rdf:Description> </rdf:RDF>
And here's how to express the same within the JSON format specified by OSLC Core.
Because we already represent valueType Resource as a JSON object,
we can simply add annotating property-values directly into that.
In this case, adding terms:expirationDate
to the terms:subscribesTo
object.
{ "prefixes" : { "terms": "http://example.com/terms/", "oslc": "http://open-services.net/ns/core#", "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#" }, "rdf:about" : "http://example.com/customers/4321", "rdf:type" : { "rdf:resource" : "http://example.com/terms/Customer" }, "terms:subscribesTo" : [{ "rdf:resource" : "http://example.com/magazines/Field_and_Stream", "terms:expirationDate" : "2010-06-03" "terms:annualPriceUSD" : 23.95, "terms:delivery" : { "rdf:resource" : "http://example.com/terms/online" } }, { "rdf:resource" : "http://example.com/magazines/Cat_Fancy", "terms:expirationDate" : "2010-01-22" "terms:annualPriceUSD" : 15.95, "terms:delivery" : { "rdf:resource" : "http://example.com/terms/mail" } }] }
Although the approaches above work to allow anchors to represent links with properties, reification can have entailment and inferencing issues. When there is a need to reify a statement in order to make statements about the stagement (called hearsay), this may be an indication that there is a missing class in the RDF vocabulary. Rather than reifying the statement, the modeler can create a separate class and create specific relationships to that class. That may actually improve the model. The example above could be modeled by introducing a Subscription to capture information about a customer and their magazine subscriptions. This is sometimes called an associative object.
@prefix terms: <http://example.com/terms/> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . <http:terms:Subscription> a rdf:Class. <#s1> a terms:Subscription; terms:magazine <http://example.com/magazines/Cat_Fancy> ; terms:subscriber <http://example.com/customers/4321> ; terms:annualPriceUSD "15.95" ; terms:delivery terms:online ; terms:expirationDate "2010-01-22" . <#s2> a terms:Subscription ; terms:magazine <http://example.com/magazines/Field_and_Stream> ; terms:subscriber <http://example.com/customers/4321> ; terms:annualPriceUSD "23.95" ; terms:delivery terms:online ; terms:expirationDate "2010-06-03" .
In this example, the Subscription subject has all the required information including the magazine, subscriber, anual price, etc. There is no need to reify any statements. A simple query will provide the list of magazines a customer subscribes to.
There are also some anti-patterns that clients and servers should avoid.
Blank nodes may be a convenient shorthand to use in examples - especially in Turtle where the [ ... ] syntax makes blank nodes easy to use. However, blank nodes may make queries and updates much harder, since there is no way to reference a specific blank node later. Introducing an explicit resource with its own URI is usually better practice.
Below is an example of a Blog Entry resource with a blank node for an uploaded-file resource.
@prefix dcterms: <http://purl.org/dc/terms/> . @prefix blog: <http://open-services.net/ns/bogus/blog#> . <http://example.com/blogs/entry/5> a blog:BlogEntry ; dcterms:title "New Wink release available" ; blog:attachment [ a blog:UploadedFile ; dcterms:title "wink-0.9.6.jar" ] .
It would be better to represent the uploaded-file resource with an explicit URI. Note that having an explicit URI does not mean the resource has to be sent in a different HTTP request; in this example, we use a hash URI to have the uploaded-file resource returned in the same HTTP request as its parent blog entry resource.
@prefix dcterms: <http://purl.org/dc/terms/> . @prefix blog: <http://open-services.net/ns/bogus/blog#> . <http://example.com/blogs/entry/5> a blog:BlogEntry ; dcterms:title "New Wink release available" ; blog:attachment <#file> . <#file> a blog:UploadedFile ; dcterms:title "wink-0.9.6.jar" .
Feedback should be directed to the OSLC Core Workgroup mailing-list. TBD - put link here.