Collections in RDF/XML
Introduction
We are defining RDF/XML representations for all resources in the EMS 1.0 specification. Many resources contain groups of other resources. For example, a project may contain one or more sets of alternative assumptions for how the project is to be executed, each of which may be estimated and compared. Projects in general track many metrics, each of which may have an estimate. Many more examples are easily found. It is therefore appropriate to establish guidelines for how to represent collections to give the EMS 1.0 specification more internal self-consistency so that it is easier for adopters to understand. Similarly, it is desirable to establish guidelines across the family of OSLC specifications for the same reason since adopters of one specification are likely to adopt others. The following discussion compares two approaches.
RDF defines a
container vocabulary where container refers to both open and closed groups of members. RDF uses collection to mean a container whose membership is closed to the resources explicitly asserted to be members. In the following we are sloppy, and use collection to mean container. If this sloppiness bothers people, we should adopt a uniform terminology at OSLC, e.g. line up with the RDF terminology.
Note that the RDF Primer discusses this design consideration. Even though RDF defines a collection vocabulary, the use of collection resources is not always the best choice:
"Sometimes there are clear alternatives to using these RDF container types. For example, a relationship between a particular resource and a group of other resources could be indicated by making the first resource the subject of multiple statements using the same property. This is structurally different from the resource being the subject of a single statement whose object is a container containing multiple members. In some cases, these two structures may have equivalent meaning, but in other cases they may not. The choice of which to use in a given situation should be made with this in mind."
At a high level, there are three main design alternatives:
- Direct Membership: Represent members of a collection as direct properties of the subject resource that contains the collection. The type of membership is expressed using an some property of the subject, and each member represent is the object of a statement involving it and the containing resource, using that property.
- Collection Resources: Represent the collection as an explicit resource. Use the RDF vocabulary to describe the type collection and membership.
- Factory Resources: This is a hybrid of the above two designs. A factory resource provides a place to create new resources using a POST request, and to list collections of related resources using a GET request with query parameters. The relation between a resource and its parent should be normally expressed as direct member, i.e. the parent is the subject of a statement that relates it to the contained object. There is one statement per member, i.e. the collection is implicitly defined using a multi-valued property of the parent. Introduce explict collection resources only when the collection has additional semantics, e.g. that the order of members is significant, or that the members represent alternatives. Use the RDF container types for this purpose.
In the following discussion we'll use the example of a Project resource. A Project may contain a zero or more alternative EstimateAssumptions resource. An EstimationAssumptions resource may contain a set of zero of more Estimate resources.
Direct Membership
This approach is somewhat simpler since it does not require the introduction of additional resources. Members can be added to the collection by POSTing a resource of that type to the containing resource URI.
For example, a Project directly contains the EstimateAssumptions resources via the hasEstimationAssumptions property. An EstimateAssumptions resource directly contains the Estimate resources via the hasEstimate property. The following illustrates this design:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Project
rdf:about="http://braintwistors.example.com/Project/4201">
<dc:title>Tsunami 1.0</dc:title>
<dc:description>
The goal of this project is to create a web version of
Tsunami, a Japanese logic puzzle, in order to drive traffic
to the BrainTwistors Corp. website and increase advertising
revenue. Future plans include developing free iPhone,
BlackBerry, and Nintendo DS versions, and charging for
puzzle downloads.
</dc:description>
<ems:hasEstimationAssumptions>
<ems:EstmationAssumptions
rdf:about="http://braintwistors.example.com/EstmationAssumptions/4202">
<dc:title>Complete project within 6 months.</dc:title>
<ems:hasEstimate>
<ems:Estimate ems:unitofMeasure="month"
rdf:about="http://braintwistors.example.com/Estmate/4203">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/schedule#duration" />
<ems:hasValue>6</ems:hasValue>
</ems:Estimate>
</ems:hasEstimate>
<ems:hasEstimate>
<ems:Estimate ems:unitofMeasure="loc"
rdf:about="http://braintwistors.example.com/Estmate/4204">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/size#esloc" />
<ems:hasValue>50000</ems:hasValue>
</ems:Estimate>
</ems:hasEstimate>
</ems:EstmationAssumptions>
</ems:hasEstimationAssumptions>
</ems:Project>
</rdf:RDF>
One major disadvantage of this approach is that the XML, although relatively flat, could get long and complex. This problem could be addressed by defining GET requests that supported selection and filtering. Also, since a resource may contain many different types of collection, the specification and code for managing the resource might get complex. One advantage is that you can retrieve everything with a single GET.
Collection Resources
In this approach, explicit collection resources are used. We introduce EstimationAssumptionsCollection and EstimateCollection:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Project
rdf:about="http://braintwistors.example.com/Project/4201">
<dc:title>Tsunami 1.0</dc:title>
<dc:description>
The goal of this project is to create a web version of
Tsunami, a Japanese logic puzzle, in order to drive traffic
to the BrainTwistors Corp. website and increase advertising
revenue. Future plans include developing free iPhone,
BlackBerry, and Nintendo DS versions, and charging for
puzzle downloads.
</dc:description>
<ems:hasEstimationAssumptions>
<ems:EstimationAssumptionsCollection
rdf:about="http://braintwistors.example.com/EstimationAssumptionsCollection/4210">
<rdf:type
rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt" />
<rdf:li>
<ems:EstmationAssumptions
rdf:about="http://braintwistors.example.com/EstmationAssumptions/4202">
<dc:title>
Complete project within 6 months.
</dc:title>
<ems:hasEstimateCollection>
<ems:EstimateCollection
rdf:about="http://braintwistors.example.com/EstimationCollection/4220">
<rdf:type
rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag" />
<rdf:li>
<ems:Estimate
ems:unitofMeasure="month"
rdf:about="http://braintwistors.example.com/Estmate/4203">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/schedule#duration" />
<ems:hasValue>6</ems:hasValue>
</ems:Estimate>
</rdf:li>
<rdf:li>
<ems:Estimate
ems:unitofMeasure="loc"
rdf:about="http://braintwistors.example.com/Estmate/4204">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/size#esloc" />
<ems:hasValue>
50000
</ems:hasValue>
</ems:Estimate>
</rdf:li>
</ems:EstimateCollection>
</ems:hasEstimateCollection>
</ems:EstmationAssumptions>
</rdf:li>
</ems:EstimationAssumptionsCollection>
</ems:hasEstimationAssumptions>
</ems:Project>
</rdf:RDF>
Members are added by POSTing a resource to the collection resource URI. One disadvantage of this approach is that the XML gets deeply nested. This can be addressed by limiting the information returned to the top-level properties and providing links to the representations of the contained collection resources. Here is the limited representation of the top-level Project resource:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Project
rdf:about="http://braintwistors.example.com/Project/4201">
<dc:title>Tsunami 1.0</dc:title>
<dc:description>
The goal of this project is to create a web version of
Tsunami, a Japanese logic puzzle, in order to drive traffic
to the BrainTwistors Corp. website and increase advertising
revenue. Future plans include developing free iPhone,
BlackBerry, and Nintendo DS versions, and charging for
puzzle downloads.
</dc:description>
<!-- use links for collection-valued properties -->
<ems:hasEstimationAssumptions
rdf:resource="http://braintwistors.example.com/EstimationAssumptionsCollection/4210" />
</ems:Project>
</rdf:RDF>
Here is the EstimationAssumptionsCollection resource:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:EstimationAssumptionsCollection
rdf:about="http://braintwistors.example.com/EstimationAssumptionsCollection/4210">
<rdf:type
rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Alt" />
<rdf:li>
<ems:EstmationAssumptions
rdf:about="http://braintwistors.example.com/EstmationAssumptions/4202">
<dc:title>Complete project within 6 months.</dc:title>
<!-- use links for collection-valued properties -->
<ems:hasEstimateCollection
rdf:resource="http://braintwistors.example.com/EstimationCollection/4220" />
</ems:EstmationAssumptions>
</rdf:li>
</ems:EstimationAssumptionsCollection>
</rdf:RDF>
Here is the EstimateCollection resource:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:EstimateCollection
rdf:about="http://braintwistors.example.com/EstimationCollection/4220">
<rdf:type
rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag" />
<rdf:li>
<ems:Estimate ems:unitofMeasure="month"
rdf:about="http://braintwistors.example.com/Estmate/4203">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/schedule#duration" />
<ems:hasValue>6</ems:hasValue>
</ems:Estimate>
</rdf:li>
<rdf:li>
<ems:Estimate ems:unitofMeasure="loc"
rdf:about="http://braintwistors.example.com/Estmate/4204">
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/size#esloc" />
<ems:hasValue>50000</ems:hasValue>
</ems:Estimate>
</rdf:li>
</ems:EstimateCollection>
</rdf:RDF>
Factory Resources
In this design the service has a set of factory resources that are used to create new resource instances using POST, and to retrieve lists of related resources using GET with query parameters. Collections are normally represented by multi-value properties that relate the parent (subject) to zero or more members (object). Introduce explicit collection resources only when the collection has additional semantic, e.g. when the order of members is significant or the collections represents alternatives.
This design organizes resources into a three-level hierarchy. The top level is the overall service, e.g. EMS 1.0. The service contains a set of factories which are used to create and list instances of a specific type, e.g. ems:Project, ems:Estimate. The service-factory-instance pattern is analogous to catalog-table-row in databases. This pattern is used in other popular REST services including the
Atom Publishing Protocol and
Rails Active Resource.
Here is the top-level service resource for EMS 1.0 which contains links to its factory resources:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Service rdf:about="http://braintwistors.example.com/ems/v1.0">
<dc:title>
BrainTwistors Corp. Estimation and Measurement Service
</dc:title>
<dc:description>
This services provides an interface to BrainTwistors Corp.
software development project estimates and measurements
using the OSLC EMS 1.0 specification.
</dc:description>
<ems:hasEstimateFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estimate" />
<ems:hasEstimationAssumptionsFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/EstimationAssumptions" />
<ems:hasProjectFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project" />
<!-- other factories have been omitted for brevity -->
</ems:Service>
</rdf:RDF>
The above service resource provides an entry point for discovering all the resources managed by the service. The service resource is like the home page of a Web application. To list all the instances of a given type, GET its factory URI. For example, here is the list of all Project resource instances which is obtained by a GET on the Project factory URI:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:ProjectFactory
rdf:about="http://braintwistors.example.com/ems/v1.0/Project">
<dc:title>
Project factory for BrainTwistors Corp. Estimation and
Measurement Service
</dc:title>
<dc:description>
This factory provides an interface to BrainTwistors Corp.
Project resources using the OSLC EMS 1.0 specification.
</dc:description>
<rdf:li
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project/4201" />
<rdf:li
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project/1379" />
<rdf:li
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project/3141" />
<!-- other Project resources have been omitted for brevity -->
</ems:ProjectFactory>
</rdf:RDF>
Each Project resource instance is linked as a member of the Project factory resource. The
EstimationAssumptions? and Estimate factories have similar structure. The service, factory, and instance resources are all connected via links. The service links to each factory. Each factory links to each of its member instances. Each instance links back to its factory which links back to its service. In addition, some resource types are subordinate to others. Here, both
EstimateAssumptions? and Estimate are subordinate to Project, and are linked to it.
To get the representation of a Project, GET its linked URI. Here is a Project resource which contains a Estimate and EstimationAssumptions resources:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Project
rdf:about="http://braintwistors.example.com/ems/v1.0/Project/4201">
<dc:title>Tsunami 1.0</dc:title>
<dc:description>
The goal of this project is to create a web version of
Tsunami, a Japanese logic puzzle, in order to drive traffic
to the BrainTwistors Corp. website and increase advertising
revenue. Future plans include developing free iPhone,
BlackBerry, and Nintendo DS versions, and charging for
puzzle downloads.
</dc:description>
<ems:inProjectFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project" />
<ems:hasEstimate
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estmate/4203" />
<ems:hasEstimate
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estmate/4204" />
<ems:hasEstimationAssumptions
rdf:resource="http://braintwistors.example.com/ems/v1.0/EstmationAssumptions/4202" />
<!-- other properties of this project resource have been omitted for brevity -->
</ems:Project>
</rdf:RDF>
Here is an EstimateAssumptions resource which contains Estimate resources:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:EstimationAssumptions
rdf:about="http://braintwistors.example.com/ems/v1.0/EstmationAssumptions/4202">
<dc:title>Complete project within 6 months.</dc:title>
<ems:inEstimationAssumptionsFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/EstimationAssumptions" />
<ems:inProject
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project/4201" />
<ems:hasEstimate
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estmate/4203" />
<ems:hasEstimate
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estmate/4204" />
</ems:EstimationAssumptions>
</rdf:RDF>
Here is an Estimate resource:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ems="http://open-services.net/ns/ems#">
<ems:Estimate ems:unitofMeasure="month"
rdf:about="http://braintwistors.example.com/ems/v1.0/Estmate/4203">
<ems:inEstimateFactory
rdf:resource="http://braintwistors.example.com/ems/v1.0/Estimate" />
<ems:inProject
rdf:resource="http://braintwistors.example.com/ems/v1.0/Project/4201" />
<ems:predicts
rdf:resource="http://open-services.net/ns/ems/schedule#duration" />
<ems:hasValue>6</ems:hasValue>
</ems:Estimate>
</rdf:RDF>
Recommendation
The factory resource approach seems to be the cleanest. It provides a simple way to create and list resource instances of a given type. The use of direct membership to define implicit collections is the simplest approach since it avoids the introduction of additional collection resources. Only where collections have additional semantics should explicit collection resources be introduced.
While RDF/XML can be used to represent resources, care should be taken to make a distinction between resource representations and descriptions of resources. A GET request on a URI that does not have query parameters should return a resource representation for that URI. However, a URI with query parameters is a different URI and should be used to GET a description of the resource associated with the plain URI, which may include descriptions of related resources.
Comments
Enter your comments here:
There are a couple of disadvantages with both of these approaches. One is that there is special server handing of POST. Another is that the opposite of POST, DELETE (REMOVE), is hard to specify. I will attach a Word document I wrote that outlines an alternative to the designs documented here.
--
MartinNally - 20 Jul 2009
Another simple rule is to consider the semantics of the logical n-ary property itself; if there are specific semantics, such as the need to order the properties, or to maintain set semantics then an explicit collection is warranted, else simply listing the properties in an n-ary fashion is simpler.
--
SimonJohnston - 21 Jul 2009
I reviewed Martin's attachment and exchange emails. The result has been another proposal which is a hybrid of the direct membership and collection resource designs. In this approach, direct membership is used, but for each main resource type, a global collection is used. You can POST to create instances and GET with a query to retrieve interesting subsets of resources.
--
ArthurRyman - 23 Jul 2009
These examples would be much more easily understood if you used a RDF notation like n3 (or turtle), that is less verbose, and much more human friendly, still being plain RDF structurally speaking (see
http://www.w3.org/2007/02/turtle/primer/ for example).
--
OlivierBerger - 22 Oct 2009
I think it is not exactly clear what question this document is trying to answer. I think I understand it deals with REST interaction with RDF resources, but in another context, the reasoning may be different. In particular, the 2 first approach seem completely generic, i.e. applying in static contexts, whereas the last one (factory) seems to apply for operations... it may need some more clarification.
Also, (I haven't really understood all the details of the recommendations, that would require a second read), I think that the
LinkedData? principles may help in some aspects maybe (see for instance
http://www4.wiwiss.fu-berlin.de/bizer/pub/LinkedDataTutorial/).
For instance, about the description of resources or description of documents sitting at a URL (last part of the recommendation, if I got it right), content-negociation and URI dereferencing are common patterns in the
SemanticWeb? I think.
--
OlivierBerger - 22 Oct 2009