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

function.datashape.ppath.rq Maven / Gradle / Ivy

Go to download

Corese is a Semantic Web Factory (triple store and SPARQL endpoint) implementing RDF, RDFS, SPARQL 1.1 Query and Update.

The newest version!
#
# Data Shape Property Path Interpreter
# RDF Path expression are compiled and stored as LDScript list by ppathparser
#
# Olivier Corby - Wimmics Inria I3S - 2016-2019
#
prefix sh:    
prefix xsh:   
prefix jc:   



@import 

#
# Return list of nodes related to node ?s by path ?p
# ?s is subject, ?p is PP expression
# ?s = us:John ; ?p = [sh:zeroOrMorePath foaf:knows]
#
function dt:list sh:ppath(s, p){  
    sh:path(sh:shaclGraph(), s, sh:getPPath(p), false)
}

function dt:list sh:path(dt:graph shape, s, p){  
    #xt:print("path:", sh:getPath(shape, p));
    sh:path(shape, s, sh:getPath(shape, p), false)
}



# user api, evaluate SHACL path in SHACL RDF format
function sh:pathfinder(path, node) {
    sh:evalpath(node, sh:getPPath(path))
}

function sh:pathfinder(path, node, asubject) {
    sh:evalpath(asubject, node, sh:getPPath(path))
}


# user api, evaluate SHACL path in compiled path format
function sh:cpathfinder(path, node) {
    sh:evalpath(node, path)
}

function sh:cpathfinder(path, node, asubject) {
    sh:evalpath(asubject, node, path)
}



#
# Evaluate PP p as a list
# Return list of target nodes that match the path
# inv = true means within inverse path
#
function dt:list sh:path(shape, node, exp, xsd:boolean inv){
    sh:evalpath(xt:list(), node, node, exp, inv, sh:null)
}


#
# Public extension function to be used out of SHACL
# evaluate path compiled as dt:list
#
function sh:evalpath(node, exp) {
    sh:evalpath(xt:list(), node, node, exp, false, sh:null)
}


function sh:evalpath(asubject, node, exp) {
    sh:evalpath(xt:list(), asubject, node, exp, false, sh:null)
}


# url = sh:null || server URL
# if null, triple patterns are evaluated on local dataset
# if not null, triple patterns are evaluated on SPARQL endpoint url with service url { s p o }
# focus is argument for (us:g1 us:g2) like select from
#
function dt:list sh:evalpath(focus, asubject, node, exp, xsd:boolean inv, url){
  if (isExtension(exp)) { # dt:list
     let ((oper path) = exp) {      
       return(funcall(oper, focus, asubject, node, path, inv, url))
     }  
  }
  else { # URI or *
     return(sh:pathProperty(focus, asubject, node, exp, inv, url))
  } 
}


# exp is a list of path expressions
function dt:list sh:zeroOrOnePath(focus, asubject, node, exp, xsd:boolean inv, url){
    let (nodeList = sh:evalpath(focus, asubject, node, exp, inv, url)){
        if (xt:member(node, nodeList), 
            return(nodeList), 
            return(xt:cons(node, nodeList)))
    }
}

function dt:list sh:zeroOrMorePath(focus, asubject, node, exp, xsd:boolean inv, url){
    sh:rec(focus, asubject, node, exp, xt:list(node), inv, url)
}

function dt:list sh:oneOrMorePath(focus, asubject, node, exp, xsd:boolean inv, url){
    sh:rec(focus, asubject, node, exp, xt:list(), inv, url)
}

#
# ?p is a PP expression exp
# compute exp*
# ?res is the list of nodes already reached by exp*
# ?res prevents loops
#
function dt:list sh:rec(focus, asubject, node, exp, dt:list res, xsd:boolean inv, url){
    let (nodeList = sh:evalpath(focus, asubject, node, exp, inv, url)){
        if (xt:size(nodeList) = 0){ return(res) }
        else {
            for (next in nodeList){
                if (! xt:member(next, res)){
                    xt:add(res, next) ; 
                    sh:rec(focus, asubject, next, exp, res, inv, url)
                }             
            } ;
            return(res)             
        }
    }
}


#
# s ^exp
# inverse PP expression
#
function dt:list sh:inversePath(focus, asubject, node, exp, xsd:boolean inv, url){
    sh:evalpath(focus, asubject, node, exp, ! inv, url)
}


#
# (sh:sequencePath (exp .. exp))
# exp = (exp .. exp)
#
function dt:list sh:sequencePath(focus, asubject, node, exp, xsd:boolean inv, url){
    if (inv) {
        return(sh:seqlist(focus, asubject, node, sh:reverse(exp), inv, url))
    }
    else{
        return(sh:seqlist(focus, asubject, node, exp, inv, url))
    }
}

# PRAGMA: correct when xsh:from is first statement 
#
function sh:reverse(exp) {
    if (sh:isFocus(xt:get(exp, 0)), 
        xt:cons(xt:get(exp, 0), xt:reverse(xt:rest(exp))), 
        xt:reverse(exp))
}


#
# Recursive traversal of sequence list expList
# recurse on xt:rest(expList)
# when sequence starts with [xsh:from (us:g1 us:g2)]
# rec call with focus = (us:g1 us:g2) like select from us:g1 us:g2
#
function dt:list sh:seqlist(focus, asubject, node, dt:list expList, xsd:boolean inv, url) {
    if (xt:size(expList) = 0) {
        # reach end of sequence: add target node subject
        return(xt:list(node))
    }
    else {
        let ((firstExp | restExpList) = expList) {
            if (sh:isFocus(firstExp)) {
                # rec call with from
                sh:seqlist(sh:getFocus(firstExp), asubject, node, restExpList, inv, url)
            }
            else {
                let (nodeList = sh:evalpath(focus, asubject, node, firstExp, inv, url)) { 
                    return (sh:seqlistmap(focus, asubject, nodeList, restExpList, inv, url))
                }
            }
        }
    }
}

# [xsh:from (us:g1 us:g2)]
# 
function sh:isFocus(exp) {
    if (isExtension(exp)) {
        let ((name rest) = exp) {
            if (name = xsh:function) {
                let ((oper arg) = rest) {
                    if (oper = xsh:from) {
                        return (true)
                    }
                }
            }
        }
    } ;
    return (false)
}

# [xsh:from (us:g1 us:g2)]
# return (us:g1 us:g2)
#
function sh:getFocus(exp) {
    let ((name rest) = exp,
         (oper arg) = rest) {
            return (arg)
    }
}

# if next exp is service, we can execute it with values nodeList for focus nodes
#
function dt:list sh:seqlistmap(focus, asubject, nodeList, dt:list expList, xsd:boolean inv, url) {
    let (res = xt:list()) {
        for (next in nodeList) { 
            let (list = sh:seqlist(focus, asubject, next, expList, inv, url)) {
                # merge removes duplicate nodes
                set(res = xt:merge(res, list))
            }
        } ;
        return (res)
    }
}




# p = (sh:alternativePath (exp .. exp))
function dt:list sh:alternativePath(focus, asubject, node, exp, xsd:boolean inv, url){
    let (expList = exp) { 
        #return(mapmerge(sh:pathmap, expList, xt:list(focus), asubject, node, inv, url))
        return(mapmerge(sh:pathmap, expList, focus, asubject, node, inv, url))
    }
}

function dt:list sh:pathmap(exp, focus, asubject, node, xsd:boolean inv, url){
    sh:evalpath(focus, asubject, node, exp, inv, url)
}

# TODO: check inv
function dt:list sh:negativePath(focus, asubject, s, exp, inv, url){
    let (select ?s ?exp (aggregate(?o) as ?l) 
         where  { values ?exp {undef} ?s ?p ?o filter (?p != ?exp) }){
        return(?l)
    }
}


function dt:list sh:pathProperty(focus, asubject, node, p, xsd:boolean inv, url){
    if (url = sh:null) {
        if (inv) {
            return(sh:inverse(focus, node, p))
        }
        else if (isLiteral(p)) { # p = *
            return (sh:star(node)) 
        }
        else {
            return(sh:step(focus, node, p))    
        }

    }
    else if (inv) {
            return(sh:inverseService(node, p, url))
        }
        else if (isLiteral(p)) { # p = *
            return (sh:starService(node, url)) 
        }
        else {
            return(sh:predicateService(node, p, url))    
        }
}

function dt:list sh:step(focus, node, apredicate) {
    if (xt:size(focus) > 0) {
        xt:objects(node, apredicate, bnode(), focus)
    }
    else {
        let (select (aggregate(distinct ?object) as ?list) node apredicate
             where { ?node ?apredicate ?object }) {
                return (list)
        }
    }
}

function dt:list sh:step2(focus, node, apredicate) {
    xt:objects(node, apredicate, bnode(), focus)
}


function dt:list sh:inverse(focus, node, apredicate) {
    if (xt:size(focus) > 0) {
        xt:subjects(bnode(), apredicate, node, focus)
    }
    else {
        let (select (aggregate(distinct ?subject) as ?list) node apredicate
             where { ?subject ?apredicate ?node }) {
                return (list)
        }
    }
}

function dt:list sh:inverse2(focus, node, apredicate){
    xt:subjects(bnode(), apredicate, node, focus)
}

function sh:objects(focus, node, apredicate) {
    maplist(xt:object, xt:edges(node, apredicate, bnode(), focus))
}

function sh:subjects(focus, node, apredicate) {
    maplist(xt:subject, xt:edges(bnode(), apredicate, node, focus))
}

function dt:list sh:predicate2(?s, ?p){
    let (select ?s ?p (aggregate(?o) as ?l) where  { ?s ?p ?o }){
        return(?l)
    }
}

function dt:list sh:star(?s){
    let (select ?s (aggregate(?o) as ?l) where  { ?s ?p ?o }){
        return(?l)
    }
}



function dt:list sh:inverse2(?o, ?p){
    let (select ?o ?p (aggregate(?s) as ?l) where  { ?s ?p ?o }){
        return(?l)
    }
}

function dt:list sh:predicateService(?s, ?p, ?url){
    if (us:trace(), xt:print("predicate service:", ?url, ?s, ?p), true);
    if (isBlank(?s)) { return(xt:list()) } ;
    let (select ?s ?p ?url (aggregate(?o) as ?l) where  { service ?url { ?s ?p ?o } }){
    if (us:trace(), xt:print("list:", l), true);
        return(?l)
    }
}

function dt:list sh:starService(?s, ?url){
    if (us:trace(), xt:print("predicate service:", ?url, ?s), true);
    if (isBlank(?s)) { return(xt:list()) } ;
    let (select ?s ?url (aggregate(?o) as ?l) where  { service ?url { ?s ?p ?o } }){
    if (us:trace(), xt:print("list:", l), true);
        return(?l)
    }
}

function dt:list sh:inverseService(?o, ?p, ?url){
    if (isBlank(?o)) { return(xt:list()) } ;
    let (select ?o ?p ?url (aggregate(?s) as ?l) where  { service ?url { ?s ?p ?o } }){
        return(?l)
    }
}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy