/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.riot.process.inf;
import java.util.List ;
import org.apache.jena.graph.Node ;
import org.apache.jena.vocabulary.RDF ;
/** Apply a fixed set of inference rules to a stream of triples.
* This is inference on the A-Box (the data) with respect to a fixed T-Box
* (the vocabulary, ontology).
* <ul>
* <li>rdfs:subClassOf (transitive)</li>
* <li>rdfs:subPropertyOf (transitive)</li>
* <li>rdfs:domain</li>
* <li>rdfs:range</li>
* </ul>
*
* Usage: call process(Node, Node, Node), outputs to derive(Node, Node, Node).
*/
abstract class InferenceProcessorRDFS
{
// Calculates hierarchies (subclass, subproperty) from a model.
// Assumes that model has no metavocabulary (use an inferencer on the model first if necessary).
// Todo:
// rdfs:member
// list:member ???
// Todo:
// rdfs:member
// list:member ???
// Work in NodeID space? But Node id caching solves most of the problems.
// Expanded hierarchy:
// If C < C1 < C2 then C2 is in the list for C
static final Node rdfType = RDF.type.asNode() ;
private final InferenceSetupRDFS state ;
public InferenceProcessorRDFS(InferenceSetupRDFS state)
{
this.state = state ;
}
public void process(Node s, Node p, Node o)
{
subClass(s,p,o) ;
subProperty(s,p,o) ;
// domain() and range() also go through subClass processing.
domain(s,p,o) ;
range(s,p,o) ;
}
public abstract void derive(Node s, Node p, Node o) ;
/*
* [rdfs8: (?a rdfs:subClassOf ?b), (?b rdfs:subClassOf ?c) -> (?a rdfs:subClassOf ?c)]
* [rdfs9: (?x rdfs:subClassOf ?y), (?a rdf:type ?x) -> (?a rdf:type ?y)]
*/
final private void subClass(Node s, Node p, Node o)
{
if ( p.equals(rdfType) )
{
List<Node> x = state.transClasses.get(o) ;
if ( x != null )
for ( Node c : x )
derive(s,p,c) ;
}
}
// Rule extracts from Jena's RDFS rules etc/rdfs.rules
/*
* [rdfs5a: (?a rdfs:subPropertyOf ?b), (?b rdfs:subPropertyOf ?c) -> (?a rdfs:subPropertyOf ?c)]
* [rdfs6: (?a ?p ?b), (?p rdfs:subPropertyOf ?q) -> (?a ?q ?b)]
*/
private void subProperty(Node s, Node p, Node o)
{
List<Node> x = state.transProperties.get(p) ;
if ( x != null )
{
for ( Node p2 : x )
derive(s, p2, o) ;
}
}
/*
* [rdfs2: (?p rdfs:domain ?c) -> [(?x rdf:type ?c) <- (?x ?p ?y)] ]
* [rdfs9: (?x rdfs:subClassOf ?y), (?a rdf:type ?x) -> (?a rdf:type ?y)]
*/
final private void domain(Node s, Node p, Node o)
{
List<Node> x = state.domainList.get(p) ;
if ( x != null )
{
for ( Node c : x )
{
derive(s, rdfType, c) ;
subClass(s, rdfType, c) ;
}
}
}
/*
* [rdfs3: (?p rdfs:range ?c) -> [(?y rdf:type ?c) <- (?x ?p ?y)] ]
* [rdfs9: (?x rdfs:subClassOf ?y), (?a rdf:type ?x) -> (?a rdf:type ?y)]
*/
final private void range(Node s, Node p, Node o)
{
// Mask out literal subjects
if ( o.isLiteral() )
return ;
// Range
List<Node> x = state.rangeList.get(p) ;
if ( x != null )
{
for ( Node c : x )
{
derive(o, rdfType, c) ;
subClass(o, rdfType, c) ;
}
}
}
}