Useful data needs consistent structure:
Detect and correct errors:
@prefix : <http://www.w3.org/2012/12/rdf-val/SOTA-ex#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/'> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<issue7> a :Issue , :SecurityIssue ;
:state :unassigned ;
:reportedBy <user6> , <user2> ; # cardinality 1
:reportedOn "2012-12-31T23:57:00"^^xsd:dateTime ;
:reproducedBy <user2>, <user1> ;
:reproducedOn "2012-11-31T23:57:00"^^xsd:dateTime ;
# reproduced before being reported
:related <issue4>, <issue3>, <issue2> .
# referenced issues not included
<issue4> # a ??? missing type arc
:state :unsinged ; # misspelled
# :reportedBy ??? - missing
:reportedOn "2012-12-31T23:57:00"^^xsd:dateTime .
<user2> a foaf:Person ;
foaf:givenName "Alice" ;
foaf:familyName "Smith" ;
foaf:phone <tel:+1.555.222.2222> ;
foaf:mbox <mailto:alice@example.com> .
<user6> a foaf:Agent ; # should be foaf:Person
foaf:givenName "Bob" ; # foaf:familyName "???" - missing
foaf:phone <tel:+.555.222.2222> ; # malformed tel: URL
foaf:mbox <mailto:alice@example.com> .
What do users get elsewhere?
| SQL | XML | |
|---|---|---|
| missing properties | reportedBy UNSIGNED INT NOT NULL | element reportedBy { User }, |
| missing/bad type arcs | N/A | N/A |
| missing referents | FOREIGN KEY (reportedBy) REFERENCES Users(ID) | <keyref refer="UserID"> |
| inconsistent state | CHECK(reproducedOn>reportedOn) | [schematron] |
| value set violations | ENUM('unasigned', 'assigned') | attribute state { "unassigned" | "assigned" } |
in order of specificity:
ASK {
{ SELECT ?S (COUNT(*) AS ?S_c0) {
?S foaf:givenName ?o .
} GROUP BY ?S}
{ SELECT ?S (COUNT(*) AS ?S_c1) {
?S foaf:givenName ?o .
} GROUP BY ?S}
FILTER (?S_c0 = ?S_c1 &&
?S_c0 = 1)
{ SELECT ?S (COUNT(*) AS ?S_c2) {
?S ex:state ?o .
} GROUP BY ?S HAVING (COUNT(*)=1)}
{ SELECT ?S (COUNT(*) AS ?S_c3) {
?S ex:state ?o .
FILTER ((?o = ex:unassigned ||
?o = ex:assigned))
} GROUP BY ?S HAVING (COUNT(*)=1)}
FILTER (?S_c2 = ?S_c3 &&
(?S_c0 = 0 || ?S_c0 = 1))
}
{
"@context": { … },
"constraints": [{
"context": "ex:status",
"constraint": "ASK { ?s ex:assignee ?o }",
"severity": "warning",
"message": "a status of assigned requires an assignee"
}]
}
ASK {
{ SELECT ?this (COUNT(*) AS ?this_c0) {
?this foaf:givenName ?o .
} GROUP BY ?this}
{ SELECT ?this (COUNT(*) AS ?this_c1) {
?this foaf:givenName ?o .
} GROUP BY ?this}
FILTER (?this_c0 = ?this_c1 &&
?this_c0 = 1)
{ SELECT ?this (COUNT(*) AS ?this_c2) {
?this ex:state ?o .
} GROUP BY ?this HAVING (COUNT(*)=1)}
{ SELECT ?this (COUNT(*) AS ?this_c3) {
?this ex:state ?o .
FILTER ((?o = ex:unassigned ||
?o = ex:assigned))
} GROUP BY ?this HAVING (COUNT(*)=1)}
FILTER (?this_c2 = ?this_c3 &&
(?this_c0 = 0 || ?this_c0 = 1))
}
:Issue a owl:Class ; rdfs:subClassOf owl:Thing ; spin:constraint [ a spl:ObjectCountPropertyConstraint ; arg:property ex:name ; arg:minCount 1 ; arg:maxCount 1 ; ] ; spin:constraint [ a spl:ObjectCountPropertyConstraint ; arg:property ex:state ; arg:minCount 0 ; arg:maxCount 1 ; ] ; spin:constraint [ a spl:UntypedObjectPropertyConstraint ; arg:property ex:state ; ] . ex:name a owl:DatatypeProperty ; rdfs:domain my:name-status ; rdfs:range xsd:string . :ValidState a owl:Class ; rdfs:label "Valid state" ; rdfs:subClassOf owl:Thing ; . :state a owl:ObjectProperty ; rdfs:domain my:name-status ; rdfs:range ex:ValidState . :unassigned a ex:ValidState . :assigned a ex:ValidState .
Combine OWL with a premise type associated with data.
Datatype: rdfs:Literal DataProperty: ex:name ObjectProperty: ex:status Class: ex:name-status SubClassOf: ex:name exactly 1 rdfs:Literal , ex:status max 1 ({ ex:assigned , ex:unassigned }) , ex:status min 0 owl:Thing Individual: ex:assigned Individual: ex:unassigned
Not a real proposal; instead used with in a different interpretation…
OWL with unique name assumption and closed world
Datatype: rdfs:Literal DataProperty: ex:name ObjectProperty: ex:status Class: ex:name-status SubClassOf: ex:name exactly 1 rdfs:Literal , ex:status max 1 ({ ex:assigned , ex:unassigned }) , ex:status min 0 owl:Thing Individual: ex:assigned Individual: ex:unassigned
my:name-status a rs:ResourceShape ; rs:property [ rs:name "name" ; rs:propertyDefinition foaf:name ; rs:valueType xsd:string ; rs:occurs rs:Exactly-one ; ] ; rs:property [ rs:name "state" ; rs:propertyDefinition ex:state ; rs:allowedValue ex:unassigned> , ex:assigned ; rs:occurs rs:Zero-or-one ; ] .
my:name-status { ex:name xsd:string , ex:status ( ex:unassigned ex:assigned )? }
my:name-status { ex:name xsd:string , ex:status ( ex:unassigned ex:assigned )? }
Datatype: rdfs:Literal DataProperty: ex:name ObjectProperty: ex:status Class: ex:name-status SubClassOf: ex:name exactly 1 rdfs:Literal , ex:status max 1 ({ ex:assigned , ex:unassigned }) , ex:status min 0 owl:Thing Individual: ex:assigned Individual: ex:unassigned
my:name-status a rs:ResourceShape ; rs:property [ rs:name "name" ; rs:propertyDefinition foaf:name ; rs:valueType xsd:string ; rs:occurs rs:Exactly-one ; ] ; rs:property [ rs:name "state" ; rs:propertyDefinition ex:state ; rs:allowedValue ex:unassigned> , ex:assigned ; rs:occurs rs:Zero-or-one ; ] .
ASK {
{ SELECT ?S (COUNT(*) AS ?S_c0) {
?S foaf:givenName ?o .
} GROUP BY ?S}
{ SELECT ?S (COUNT(*) AS ?S_c1) {
?S foaf:givenName ?o .
} GROUP BY ?S}
FILTER (?S_c0 = ?S_c1 &&
?S_c0 = 1)
{ SELECT ?S (COUNT(*) AS ?S_c2) {
?S ex:state ?o .
} GROUP BY ?S HAVING (COUNT(*)=1)}
{ SELECT ?S (COUNT(*) AS ?S_c3) {
?S ex:state ?o .
FILTER ((?o = ex:unassigned ||
?o = ex:assigned))
} GROUP BY ?S HAVING (COUNT(*)=1)}
FILTER (?S_c2 = ?S_c3 &&
(?S_c0 = 0 || ?S_c0 = 1))
}
<Foo> { foaf:parent NONLITERAL{2} }
<X> foaf:parent [ foaf:mbox <mailto:a@example.com> ], [ foaf:mbox <mailto:a@example.com> ].
rdf:type<(?:[^<>]++|(?1))*>
review "small" requirements group.