All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aksw.jena_sparql_api.shape.ResourceShapeParserJsonObject Maven / Gradle / Ivy

There is a newer version: 3.17.0-1
Show newest version
package org.aksw.jena_sparql_api.shape;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.aksw.jena_sparql_api.concepts.Relation;
import org.aksw.jena_sparql_api.utils.Vars;

import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.shared.PrefixMapping;
import org.apache.jena.sparql.expr.E_Equals;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprVar;
import org.apache.jena.sparql.expr.NodeValue;
import org.apache.jena.sparql.syntax.ElementFilter;
import org.apache.jena.sparql.util.ExprUtils;


/*
 * http://www.grappa.univ-lille3.fr/~staworko/papers/staworko-arxiv-shex.pdf
 * 
 * E := e | a | E* | E1 or E2 | E1 and E2 
 * 
 * e = empty expression
 * and = unordered concatenation
 * or = disjunction
 * * = Kleene star
 * 
 * E? = (e or E)
 * E+ = (E and E*)
 * 
 */

// NOTE Maybe we should use the term silhouette to distinguish our approach from the shapes
// a silhouette expression could be shortened to 'silex'.
// What is the semantics of a shex??????
// [[E]]_D
// The evaluation of a silex E over a dataset D yields a graph
// This means, that a silex must be converted to a sparql query first
interface Shex {

}

// Note: could also be modeled as a constant of type ShEx
class ShexEmpty
    implements Shex
{
    
}

class ShexNav
    implements Shex
{
    private Shex base;
    private String predicate;
    private boolean isInverse;
}

abstract class ShexBase2 {
    private Shex left;
    private Shex right;
}

/**
 * Union of two shex expressions
 * 
 * @author raven
 *
 */
class ShexUnion
    extends ShexBase2
{
}

/**
 * 
 * @author raven
 *
 */
class ShexAnd
    extends ShexBase2
{
    
}


/**
 * shape: true
 * 
 * shape: 'rdfs:label'
 * 
 * 
 * shape: ['rdf:type', 'rdfs:label']
 * 
 * shape: {
 *   'rdf:type': true # Fetch rdf:type triples together with all outgoing triples of rdf:type
 * }
 * 
 * shape: {
 *   'rdf:type': false # Fetch rdf:type triples, but no further reachable triples
 * }
 *
 * shape: {
 *   '-rdf:type': ... # Prefix with '-' to navigate in inverse direction (should replace '>' which we used so far)
 * }
 *
 * shape: {
 *   '~?p = rdf:type && langMatches(lang(?o), "en")' // Prefix with ~ to use a sparql expression
 * }
 * 
 * Special attributes start with '$':
 * $filter: Set a concept for filtering the set of reached resources
 * 
 * note:
 * ['rdf:type'] is equivalent to { 'rdf:type': false }
 * 
 * shape: {
 *   'rdf:type': {
 *     $filter: '?s | ?s a owl:Class' // Only fetch types that are owl:Classes (i.e. exclude e.g. SKOS concepts),
 *     $predicates: ['rdfs:label']     
 *   }
 * }
 * 
 * Macro symbols:
 * shape: '{@literal @}spatial'
 * 
 * At {@literal @}spatial will extended with its definition.
 * 
 * 
 * @author raven
 *
 */
public class ResourceShapeParserJsonObject {
    public static final String geo = "http://www.w3.org/2003/01/geo/wgs84_pos#";
    public static final String geom = "http://geovocab.org/geometry#";
    public static final String ogc = "http://www.opengis.net/ont/geosparql#asWKT";

    
    // TODO: All these things should be resource shape objects that must be combinable
    public static final String wgs84 = "['geo:lat', 'geo:long']";
    public static final String wgs84geometry = "['geo:geometry']";
    public static final String geoSparqlLgd = "[geom:geometry: 'ogc:AsWkt']";
    
    private PrefixMapping prefixMapping;
    
    public ResourceShapeParserJsonObject(PrefixMapping prefixMapping) {
        this.prefixMapping = prefixMapping;
    }
    
    
    /**
     * String must be of format
     * [-] [~] str
     * 
     * -: If present, assume inverse direction
     * ~: If present, str is assumed to be a SPARQL expression. Otherwise, a property URI is assumed
     * 
     * 
     * @param str
     * @return
     */
    public static StepRelation parseStep(String str, PrefixMapping prefixMapping) {
        str = str.trim();
        
        // Check the first character
        char c = str.charAt(0);
        boolean isInverse = c == '-';
        
        if(isInverse) {
            str = str.substring(1);
        }
        
        c = str.charAt(0);
        boolean isExpr = c == '~';

        if(isExpr) {
            str = str.substring(1);
        }        
        
        Expr expr;
        if(isExpr) {
            expr = ExprUtils.parse(str, prefixMapping);
        } else {
            String p = prefixMapping.expandPrefix(str);
            Node np = NodeFactory.createURI(p);
            expr = new E_Equals(new ExprVar(Vars.p), NodeValue.makeNode(np));  
        }
        
        Relation relation = new Relation(new ElementFilter(expr), Vars.p, Vars.o);
        
        StepRelation result = new StepRelation(relation, isInverse);
        return result;
    }
    
    public ResourceShape parse(Object obj) {
        ResourceShapeBuilder builder = new ResourceShapeBuilder(prefixMapping);
        parse(obj, builder);
        
        ResourceShape result = builder.getResourceShape();
        return result;
    }
    
    public ResourceShape parse(Object obj, ResourceShapeBuilder builder) {
        
        if(obj == null) {
            // nothing to do
        }
        if(obj instanceof Boolean) { // true -> fetch all properties
            Boolean tf = (Boolean)obj;
            if(tf == true) {
                builder.nav(NodeValue.TRUE, true);
            }
        }
        else if (obj instanceof String) { // fetch a single property
            String str = (String)obj;
            StepRelation step = parseStep(str, prefixMapping);
            
            builder.nav(step);
        }
        else if (obj instanceof List) { // fetch an array of properties (possibly nested)c
            List list = (List)obj;
            for(Object item : list) {
                parse(item, builder);
            }
        }
        else if (obj instanceof Map) { //
            @SuppressWarnings("unchecked")
            Map map = (Map)obj;
            for(Entry entry : map.entrySet()) {
                String str = entry.getKey();
                Object o = entry.getValue();
                StepRelation step = parseStep(str, prefixMapping);
                ResourceShapeBuilder subBilder = builder.nav(step);
                parse(o, subBilder);
                
            }
        } else {
            throw new RuntimeException("Unsupported argument: " + obj);
        }
        
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy