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.