Re: Stand-alone Shapes and oslc:valueRange implemented in SPIN

Sorry for the dealy in responding. I noticed the request for shapes
folks to say what else was needed and I had to think about this for
a bit. A few comments inline.

I think you mean oslc:valueShape, or at least that's what I see in
  http://www.w3.org/Submission/2014/SUBM-shapes-20140211/#valueShape


* Holger Knublauch <holger@topquadrant.com> [2014-11-20 10:49+1000]
> [Starting a new thread on this specific solution, extending on [1] ]
> 
> I have implemented a new SPIN property function
> spin:constructViolations and a helper function
> spl:violatesConstraints, and those have allowed me to implement
> oslc:valueRange as defined by the Resource Shapes 2.0 spec. The
> implementation and an example file are attached.
> 
> In the example, we have :Issue pointing at :Person via two
> properties :assignedTo and :submittedBy. Both are Persons, but
> submitters may not have last name or email, but assignees must have
> those. This is modeled via
> 
> oslc_issue:Issue
>   rdf:type owl:Class ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:assignedTo ;
>       oslc:range oslc_issue:Person ;
>       oslc:valueRange oslc_issue:Assignee ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:submittedBy ;
>       oslc:range oslc_issue:Person ;
>       oslc:valueRange oslc_issue:Submitter ;
>     ] ;
>   rdfs:label "Issue"^^xsd:string ;
>   rdfs:subClassOf owl:Thing .
> 
> which means although the range of both properties is Person,
> different additional constraints are used depending on the context.
> Here is Assignee:
> 
> oslc_issue:Assignee
>   rdf:type owl:Class ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:occurs oslc:Exactly-one ;
>       oslc:propertyDefinition oslc_issue:email ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:occurs oslc:Exactly-one ;
>       oslc:propertyDefinition oslc_issue:lastName ;
>     ] ;
>   rdfs:comment "All assignees must have an email and a last
> name."^^xsd:string ;
>   rdfs:label "Assignee"^^xsd:string ;
>   rdfs:subClassOf oslc_issue:Person .
> 
> This :Assignee class doesn't need to be part of the actual ontology
> - it may just live in a SPIN file that isn't visible to end users.
> 
> The actual context-sensitive check behind oslc:valueRange is
> implemented using
> 
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>             ?s ?p ?o .
>         }
>         WHERE {
>             ?this ?propertyDefinition ?value .
>             (?value ?valueRange) spin:constructViolations (?s ?p ?o)
>             BIND (CONCAT("Value ", xsd:string(?value), " of property ",
>                  xsd:string(?propertyDefinition), " does not match
> the shape ",
>                  xsd:string(?valueRange)) AS ?label) .
>         }
> 
> where spin:constraintViolations essentially spawns off a recursive
> constraint checking engine to verify that the given ?value meets all
> constraints defined at the class ?valueRange. Any nested constraint
> violations get propagated forward in the surrounding CONSTRUCT. But
> nobody needs to look into those details - they can be solved by a
> shapes library.
> 
> The cost of this solution is that engines who want to support this
> would need to implement the spin:constructViolations property
> function. There is currently no official extension mechanism in
> SPARQL for property functions, but many SPARQL databases actually
> have this implemented as a de-facto standard. Yet we would need to
> somehow specify this. If we cannot use property functions (aka magic
> properties) then we could make it a normal SPARQL function that
> returns a temporary named graph or maybe just a boolean, so it will
> definitely work even with the current SPARQL language spec in one
> way or another.

Or someone could parse the shapes and compile an inclusive SPARQL
query directly.


> Anyway, the extension above is now in the TopBraid code base and
> will go into the next SPIN API for Jena too.
> 
> This means that SPIN can now be used to check an instance against a
> certain "shape" even if the instance doesn't have a corresponding
> rdf:type.

If I understand this, you can now parse resource shapes in exactly
their current form and perform the appropriate validation, perhaps
even a sublanguage of OWL that used only subclasses of restrictions
with allValuesFrom and cardinalities. This certainly makes it much
easier to use SPIN+extensions for this.


It may be a bit hard to know how easy this really is until we figure
out the language. For instance, are the cardinality constraints
qualified or unqualified?  The feedback I heard on day 1 of the F2F
was that they are qualified so multiple declarations of dc:creator

  <S> a rs:ResourceShape ;
      rs:property [
          rs:name "creator" ;
          rs:propertyDefinition dc:creator ;
          rs:valueShape <Authority> ;
          rs:occurs rs:Exactly-one ;
      ] ;
      rs:property [
          rs:name "creator" ;
          rs:propertyDefinition dc:creator ;
          rs:valueShape <Author> ;
          rs:occurs rs:Exactly-one ;
      ] ;
  .

would mean that one of each was required and, implicitly, no others.
Arthur, is that still your intention?


> I would appreciate feedback from those in the Shapes/ShEx camp. What
> else is needed?

I think the big issues with shapes as types were
  1 contextual constraints (which this addresses).
  2 conflicting constraints.

I know that your position on 2 is that they can be written in separate
RDF graphs and responding to that thread had responding to this as a
prerequisite. I'll respond to the other now.


> Thanks,
> Holger
> 
> [1] http://lists.w3.org/Archives/Public/public-data-shapes-wg/2014Nov/0193.html
> 

> # baseURI: http://open-services.net/ns/core
> # imports: http://purl.org/dc/terms/
> # imports: http://spinrdf.org/spl
> 
> @prefix oslc: <http://open-services.net/ns/core#> .
> @prefix owl: <http://www.w3.org/2002/07/owl#> .
> @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
> @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
> @prefix sp: <http://spinrdf.org/sp#> .
> @prefix spin: <http://spinrdf.org/spin#> .
> @prefix spl: <http://spinrdf.org/spl#> .
> @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
> 
> <http://open-services.net/ns/core>
>   rdf:type owl:Ontology ;
>   owl:imports <http://purl.org/dc/terms/> ;
>   owl:imports <http://spinrdf.org/spl> ;
> .
> oslc:AllowedValues
>   rdf:type rdfs:Class ;
>   rdfs:comment "Defines a set of allowed values for a defined property. This type of resource is useful when defined properties take values in large sets of standard values that are used in multiple types of resources. For example, a list of standard country codes could be stored in an oslc:AllowedValues resource."^^xsd:string ;
>   rdfs:label "Allowed values"^^xsd:string ;
> .
> oslc:AllowedValuesConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """
>         # Reports a constraint violation if ?this has any value that is not in the enumeration of allowed values
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>         }
>         WHERE {
>             ?this ?propertyDefinition ?value .
>             FILTER NOT EXISTS {
>                 ?allowedValues oslc:allowedValue ?value .
>             } .
>             BIND (CONCAT(\"Value \", xsd:string(?value), \" is not allowed for property \", xsd:string(?propertyDefinition)) AS ?label) .
>         }
>         """^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:allowedValues ;
>       spl:valueType oslc:AllowedValues ;
>       rdfs:comment "The resource containing a set of allowed values of the defined property."^^xsd:string ;
>     ] ;
>   spin:labelTemplate "The property {?propertyDefinition} must have one of the allowed values defined by {?allowedValues}."^^xsd:string ;
>   rdfs:label "Allowed values constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:Any
>   rdf:type rdfs:Class ;
>   rdfs:label "Any"^^xsd:string ;
> .
> oslc:Cardinality
>   rdf:type rdfs:Class ;
>   rdfs:label "Cardinality"^^xsd:string ;
> .
> oslc:Either
>   rdf:type oslc:Representation ;
>   rdfs:comment "There is no constraint on the representation of the object resource."^^xsd:string ;
>   rdfs:label "Either"^^xsd:string ;
> .
> oslc:Exactly-one
>   rdf:type oslc:Cardinality ;
>   oslc:maxCount 1 ;
>   oslc:minCount 1 ;
>   rdfs:comment "The defined property MUST occur exactly once. It is required and single-valued."^^xsd:string ;
>   rdfs:label "Exactly-one"^^xsd:string ;
> .
> oslc:Inline
>   rdf:type oslc:Representation ;
>   rdfs:comment "The representation of the object resource MUST be present in the representation of the described resource."^^xsd:string ;
>   rdfs:label "Inline"^^xsd:string ;
> .
> oslc:MaxSizeConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """
>         # Reports a constraint violation if ?this has a literal value that has more characters than ?maxSize
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>         }
>         WHERE {
>             ?this ?propertyDefinition ?value .
>             FILTER isLiteral(?value) .
>             FILTER (STRLEN(xsd:string(?value)) > ?maxSize) .
>             BIND (CONCAT(\"Values of property \", xsd:string(?propertyDefinition), \" cannot have more than \", xsd:string(?maxSize), \" characters, but found \", xsd:string(?value)) AS ?label) .
>         }
>         """^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:maxSize ;
>       spl:valueType xsd:integer ;
>       rdfs:comment "For string datatype properties, the maximum number of characters."^^xsd:string ;
>     ] ;
>   rdfs:label "Max size constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:OccursConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """
>         # Reports a constraint violation if ?this has an unexpected number of values (cardinality)
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>         }
>         WHERE {
>             BIND (spl:objectCount(?this, ?propertyDefinition) AS ?count) .
>             BIND (spl:object(?occurs, oslc:minCount) AS ?minCount) .
>             BIND (spl:object(?occurs, oslc:maxCount) AS ?maxCount) .
>             FILTER ((bound(?minCount) && (?count < ?minCount)) || (bound(?maxCount) && (?count > ?maxCount))) .
>             BIND (CONCAT(\"Property \", xsd:string(?propertyDefinition), \" does not match specified cardinality \", xsd:string(?occurs)) AS ?label) .
>         }
>         """^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:occurs ;
>       spl:valueType oslc:Cardinality ;
>       rdfs:comment "The number of times the defined property may occur."^^xsd:string ;
>     ] ;
>   rdfs:label "Occurs constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:One-or-many
>   rdf:type oslc:Cardinality ;
>   oslc:minCount 1 ;
>   rdfs:comment "The defined property MUST occur at least once. It is required and multi-valued."^^xsd:string ;
>   rdfs:label "One-or-many"^^xsd:string ;
> .
> oslc:Property
>   rdf:type spl:ConstraintTemplate ;
>   rdf:type spl:UnionTemplate ;
>   spin:labelTemplate "Property {?propertyDefinition}"^^xsd:string ;
>   rdfs:comment "This template serves as a single \"parent\" for all other OSLC constraint templates, so that RDF models only need to instantiate oslc:Property and put any number of other constraints into the same node."^^xsd:string ;
>   rdfs:label "Property"^^xsd:string ;
>   rdfs:subClassOf oslc:AllowedValuesConstraint ;
>   rdfs:subClassOf oslc:MaxSizeConstraint ;
>   rdfs:subClassOf oslc:OccursConstraint ;
>   rdfs:subClassOf oslc:RangeConstraint ;
>   rdfs:subClassOf oslc:ValueRangeConstraint ;
>   rdfs:subClassOf oslc:ValueTypeConstraint ;
> .
> oslc:PropertyConstraintTemplate
>   rdf:type spl:ConstraintTemplate ;
>   spin:abstract "true"^^xsd:boolean ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:optional "true"^^xsd:boolean ;
>       spl:predicate oslc:hidden ;
>       spl:valueType xsd:boolean ;
>       rdfs:comment "A hint that the defined property is not normally displayed by a user interface."^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:optional "true"^^xsd:boolean ;
>       spl:predicate oslc:isMemberProperty ;
>       spl:valueType xsd:boolean ;
>       rdfs:comment "If true then the described resource is a container and the defined property is used for container membership."^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:optional "true"^^xsd:boolean ;
>       spl:predicate oslc:name ;
>       spl:valueType xsd:string ;
>       rdfs:comment "oslc:name is used to specify the local name of the defined property. This is normally the portion of the defined property URI (see oslc:propertyDefinition) that follows the last hash (#) or slash (/)."^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:optional "true"^^xsd:boolean ;
>       spl:predicate oslc:readOnly ;
>       spl:valueType xsd:boolean ;
>       rdfs:comment "See http://www.w3.org/Submission/2014/SUBM-shapes-20140211/#readOnly"^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:optional "true"^^xsd:boolean ;
>       spl:predicate oslc:representation ;
>       spl:valueType oslc:Representation ;
>       rdfs:comment "For object properties, oslc:representation is used to specify how the object resource is represented."^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:propertyDefinition ;
>       spl:valueType rdf:Property ;
>       rdfs:comment "The property that is being constrained."^^xsd:string ;
>     ] ;
>   rdfs:comment "This class groups together all templates that are constraining a given property."^^xsd:string ;
>   rdfs:label "Property constraint template"^^xsd:string ;
>   rdfs:subClassOf spl:ConstraintTemplates ;
> .
> oslc:RangeConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """
>         # Reports a constraint violation if ?this has any value that does not have the given rdf:type
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>         }
>         WHERE {
>             {
>                 FILTER (?range != oslc:Any) .
>             } .
>             ?this ?propertyDefinition ?value .
>             FILTER (!spl:instanceOf(?value, ?range)) .
>             BIND (CONCAT(\"Value \", xsd:string(?value), \" at property \", xsd:string(?propertyDefinition), \" does not have type \", xsd:string(?range)) AS ?label) .
>         }
>         """^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:range ;
>       spl:valueType rdfs:Class ;
>       rdfs:comment "For object properties, oslc:range is used to specify an allowed rdf:type of the object resource."^^xsd:string ;
>     ] ;
>   rdfs:label "Range constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:Reference
>   rdf:type oslc:Representation ;
>   rdfs:comment "The representaton of the object resource MUST NOT be present in the representation of the described resource."^^xsd:string ;
>   rdfs:label "Reference"^^xsd:string ;
> .
> oslc:Representation
>   rdf:type rdfs:Class ;
>   rdfs:label "Representation"^^xsd:string ;
> .
> oslc:ValueRangeConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """# Reports constraint violations for any value that does not match the constraints defined at a given \"shape\" class
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
> 			?s ?p ?o .
>         }
>         WHERE {
>             ?this ?propertyDefinition ?value .
> 			(?value ?valueRange) spin:constructViolations (?s ?p ?o)
>             BIND (CONCAT(\"Value \", xsd:string(?value), \" of property \", xsd:string(?propertyDefinition), \" does not match the shape \", xsd:string(?valueRange)) AS ?label) .
>         }"""^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:valueRange ;
>       spl:valueType rdfs:Class ;
>       rdfs:comment "For object properties, oslc:valueShape is used to specify a link to resource shape that describes the object resource."^^xsd:string ;
>     ] ;
>   rdfs:label "Value range constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:ValueTypeConstraint
>   rdf:type spl:ConstraintTemplate ;
>   spin:body [
>       rdf:type sp:Construct ;
>       sp:text """
>         # Reports a constraint violation if ?this has any value that does not have the given datatype
>         CONSTRUCT {
>             _:cv a spin:ConstraintViolation ;
>                 spin:violationRoot ?this ;
>                 spin:violationPath ?propertyDefinition ;
>                 rdfs:label ?label .
>         }
>         WHERE {
>             ?this ?propertyDefinition ?value .
>             FILTER (datatype(?value) != ?valueType) .
>             BIND (CONCAT(\"Value \", xsd:string(?value), \" of property \", xsd:string(?propertyDefinition), \" does not have value type \", xsd:string(?valueType)) AS ?label) .
>         }
>         """^^xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type spl:Argument ;
>       spl:predicate oslc:valueType ;
>       spl:valueType rdfs:Datatype ;
>       rdfs:comment "For datatype properties, oslc:valueType specifies the literal value type. It MUST be one of the following individuals: rdf:XMLLiteral, xsd:boolean, xsd:dateTime, xsd:decimal, xsd:double, xsd:float, xsd:integer, xsd:string."^^xsd:string ;
>     ] ;
>   rdfs:label "Value type constraint"^^xsd:string ;
>   rdfs:subClassOf oslc:PropertyConstraintTemplate ;
> .
> oslc:Zero-or-many
>   rdf:type oslc:Cardinality ;
>   rdfs:comment "The defined property MAY occur any number of times. It is optional and multi-valued."^^xsd:string ;
>   rdfs:label "Zero-or-many"^^xsd:string ;
> .
> oslc:Zero-or-one
>   rdf:type oslc:Cardinality ;
>   oslc:maxCount 1 ;
>   rdfs:comment "The defined property MUST occur no more than once. It is optional and single-valued."^^xsd:string ;
>   rdfs:label "Zero-or-one"^^xsd:string ;
> .
> oslc:allowedValue
>   rdf:type rdf:Property ;
>   rdfs:domain oslc:AllowedValues ;
>   rdfs:label "allowed value"^^xsd:string ;
> .
> oslc:allowedValues
>   rdf:type rdf:Property ;
>   rdfs:label "allowed values"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:hidden
>   rdf:type rdf:Property ;
>   rdfs:label "hidden"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:isMemberProperty
>   rdf:type rdf:Property ;
>   rdfs:label "is member property"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:maxCount
>   rdf:type rdf:Property ;
>   rdfs:domain oslc:Cardinality ;
>   rdfs:label "max count"^^xsd:string ;
>   rdfs:range xsd:integer ;
> .
> oslc:maxSize
>   rdf:type rdf:Property ;
>   rdfs:label "max size"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:minCount
>   rdf:type rdf:Property ;
>   rdfs:domain oslc:Cardinality ;
>   rdfs:label "min count"^^xsd:string ;
>   rdfs:range xsd:integer ;
> .
> oslc:name
>   rdf:type rdf:Property ;
>   rdfs:label "name"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:occurs
>   rdf:type rdf:Property ;
>   rdfs:label "occurs"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:propertyDefinition
>   rdf:type rdf:Property ;
>   rdfs:label "property definition"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:range
>   rdf:type rdf:Property ;
>   rdfs:label "range"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:readOnly
>   rdf:type rdf:Property ;
>   rdfs:label "read only"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:representation
>   rdf:type rdf:Property ;
>   rdfs:label "representation"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:valueRange
>   rdf:type rdf:Property ;
>   rdfs:label "value range"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .
> oslc:valueType
>   rdf:type rdf:Property ;
>   rdfs:label "value type"^^xsd:string ;
>   rdfs:subPropertyOf sp:arg ;
> .

> # baseURI: http://example.org/oslc_issue
> # imports: http://open-services.net/ns/core
> 
> @prefix : <http://example.org/oslc_issue#> .
> @prefix oslc: <http://open-services.net/ns/core#> .
> @prefix oslc_issue: <http://example.org/oslc_issue#> .
> @prefix owl: <http://www.w3.org/2002/07/owl#> .
> @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
> @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
> @prefix spin: <http://spinrdf.org/spin#> .
> @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
> 
> <http://example.org/oslc_issue>
>   rdf:type owl:Ontology ;
>   owl:imports <http://open-services.net/ns/core> ;
>   owl:versionInfo "Created with TopBraid Composer"^^xsd:string ;
> .
> oslc_issue:Assignee
>   rdf:type owl:Class ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:occurs oslc:Exactly-one ;
>       oslc:propertyDefinition oslc_issue:email ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:occurs oslc:Exactly-one ;
>       oslc:propertyDefinition oslc_issue:lastName ;
>     ] ;
>   rdfs:comment "All assignees must have an email and a last name."^^xsd:string ;
>   rdfs:label "Assignee"^^xsd:string ;
>   rdfs:subClassOf oslc_issue:Person ;
> .
> oslc_issue:Issue
>   rdf:type owl:Class ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:assignedTo ;
>       oslc:range oslc_issue:Person ;
>       oslc:valueRange oslc_issue:Assignee ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:submittedBy ;
>       oslc:range oslc_issue:Person ;
>       oslc:valueRange oslc_issue:Submitter ;
>     ] ;
>   rdfs:label "Issue"^^xsd:string ;
>   rdfs:subClassOf owl:Thing ;
> .
> oslc_issue:Issue_1
>   rdf:type oslc_issue:Issue ;
>   oslc_issue:assignedTo oslc_issue:JohnDoeWithEmail ;
>   oslc_issue:submittedBy oslc_issue:John ;
>   rdfs:label "Issue 1"^^xsd:string ;
> .
> oslc_issue:John
>   rdf:type oslc_issue:Person ;
>   oslc_issue:firstName "John"^^xsd:string ;
> .
> oslc_issue:JohnDoeWithEmail
>   rdf:type oslc_issue:Person ;
>   oslc_issue:email "john@doe.com"^^xsd:string ;
>   oslc_issue:firstName "John"^^xsd:string ;
>   oslc_issue:lastName "Doe"^^xsd:string ;
> .
> oslc_issue:Person
>   rdf:type owl:Class ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:occurs oslc:Exactly-one ;
>       oslc:propertyDefinition oslc_issue:firstName ;
>       oslc:valueType xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:email ;
>       oslc:valueType xsd:string ;
>     ] ;
>   spin:constraint [
>       rdf:type oslc:Property ;
>       oslc:propertyDefinition oslc_issue:lastName ;
>       oslc:valueType xsd:string ;
>     ] ;
>   rdfs:label "Person"^^xsd:string ;
>   rdfs:subClassOf owl:Thing ;
> .
> oslc_issue:Submitter
>   rdf:type owl:Class ;
>   rdfs:label "Submitter"^^xsd:string ;
>   rdfs:subClassOf oslc_issue:Person ;
> .
> oslc_issue:assignedTo
>   rdf:type owl:ObjectProperty ;
>   rdfs:domain oslc_issue:Issue ;
>   rdfs:label "assigned to"^^xsd:string ;
>   rdfs:range oslc_issue:Person ;
> .
> oslc_issue:email
>   rdf:type owl:DatatypeProperty ;
>   rdfs:domain oslc_issue:Person ;
>   rdfs:label "email"^^xsd:string ;
>   rdfs:range xsd:string ;
> .
> oslc_issue:firstName
>   rdf:type owl:DatatypeProperty ;
>   rdfs:domain oslc_issue:Person ;
>   rdfs:label "first name"^^xsd:string ;
>   rdfs:range xsd:string ;
> .
> oslc_issue:lastName
>   rdf:type owl:DatatypeProperty ;
>   rdfs:domain oslc_issue:Person ;
>   rdfs:label "last name"^^xsd:string ;
>   rdfs:range xsd:string ;
> .
> oslc_issue:submittedBy
>   rdf:type owl:ObjectProperty ;
>   rdfs:domain oslc_issue:Issue ;
>   rdfs:label "submitted by"^^xsd:string ;
>   rdfs:range oslc_issue:Person ;
> .


-- 
-ericP

office: +1.617.599.3509
mobile: +33.6.80.80.35.59

(eric@w3.org)
Feel free to forward this message to any list for any purpose other than
email address distribution.

There are subtle nuances encoded in font variation and clever layout
which can only be seen by printing this message on high-clay paper.

Received on Tuesday, 25 November 2014 22:04:07 UTC