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

function.datashape.path.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!
#
# SHACL Interpreter 
#
# Olivier Corby - Wimmics Inria I3S - 2016-2019
#

prefix sh:   
prefix xsh:  
prefix msh: 
prefix shex: 

@import  


#
# shape: shacl graph
# sh: current shape
# vis: true if report is needed
# nodeList:  list of target nodes of shape sh
# path: path expression
# present=true: fail when path is empty, use case: qualified value shape
# 
function sh:path(report, sh, vis, nodeList, path, present) {
    if (sh:trace(), xt:print("path:", sh, path, nodeList), true);
   let (b1 = sh:pathBasic(report, sh, vis, nodeList, path, present), 
        b6 = sh:sparql(report, sh, vis, nodeList, path)
       ) {
       return (b1 &&  b6)
    }
}


#
# nodeList: target node list 
# p: the path
# oper=sh:nodeKind ; val=sh:IRI
# present = true: return false when path is empty; use case: qualified value shape
#

function sh:pathBasic(report, sh, vis, s, p, present) {
    #xt:print("path", sh, p, nodeList);
    let (res = true, 
        opt      = sh:getShapeConstraint(sh:optional, sh),
        cstList1 = sh:getShapeConstraint(sh:path1, sh),
        cstList2 = sh:getShapeConstraint(sh:path2, sh),
        cstList3 = sh:getShapeConstraint(sh:path3, sh),
        cstList4 = sh:getShapeConstraint(sh:pathextension, sh),
        b1 = xt:size(cstList1) > 0,
        b2 = xt:size(cstList2) > 0,
        b3 = xt:size(cstList3) > 0,
        b4 = xt:size(cstList4) > 0) {
        #xt:print("path:",  cstList1);
        if (! (b1 || b2 || b3 || b4)) {
            if (sh:trace(), xt:print("path:", sh, "no path constraint"), true)
        }
        else {
            #xt:print("path:", p, nodeList, opt);
            #xt:print("path:", nodeList, p);
            if (sh:trace()) {
                xt:print("path cst1:", cstList1);
                xt:print("path cst2:", cstList2);
                xt:print("path cst3:", cstList3);
                xt:print("path cst4:", cstList4)
            } ;
            xt:event("@pathShacl", sh, s, p, cstList1, cstList2, cstList3, cstList4);
                                                
           # for (s in dt:list(nodeList)) {
                            
                let (targetList = sh:ppath(s, p)) {
                    #xt:print("path:", s, p, targetList, present);
                    
                    if (b1) {
                        # present: special case for qualified value shape
                        if (present && xt:size(targetList) = 0) {
                            return(false)
                        } ;
                        
                        # use case: shex optional statement
                        if (opt     && xt:size(targetList) = 0) {
                            return (true)
                        } ;
                        
                        for (o in targetList) {
                            #if (sh:contains(sh, o)) {}
                            #else {
                            #sh:push(sh, o);
                            
                            for ((oper val) in cstList1) {
                                if (oper = sh:node) {
                                    let (detail   = vis && sh:isSetup(xsh:nodeDetail), 
                                        subReport = sh:detailReport(report, detail),
                                        suc = coalesce(sh:node(subReport, o, val, present, detail), false)) {
                                        
                                        sh:reportDetail(report, subReport, oper, sh, val, s, p, o, suc, vis, detail) ;
                                        if (! suc, set(res = false), true) 
                                    }
                                }
                                else {
                                    let (suc = coalesce(
                                                if (oper in (sh:property), 
                                                    sh:property(report, o, val, present), 
                                                    funcall(oper, o, val)),
                                                false)) {
                                                
                                            if (oper in (sh:property), true, 
                                                sh:report(report, oper, sh, s, p, o, suc, vis)) ;
                                            if (! suc, set(res = false), true) 
                                    }
                                }
                            }
                            
                            #; sh:pop()
                            #} ;
                            
                            #xt:print("res1:", sh, s, p, o, res)
                        } 
                    } ;
                                                           
                    if (b2) {
                        # sh:minCount sh:and sh:or ...
                         # use case: shex optional statement
                        if (opt     && xt:size(targetList) = 0, return (true), true);
                        
                        for ((oper val) in cstList2) {
                            let (suc = coalesce(
                            if (oper in (sh:and, sh:or, sh:xone, sh:not),  
                                sh:pathbool(report, oper, sh, vis, s, p, val, targetList, present),   
                                funcall(oper, report, sh, vis, s, p, val, targetList)),   
                            false)) {
                                if (! suc) {
                                    set(res = false) 
                                }
                            } ;
                            
                           # xt:print("res2:", sh, oper, val, s, p, res)
                        } ;
                        
                    } ;
                    
                    if (b3) {
                        # use case: shex optional statement
                        if (opt     && xt:size(targetList) = 0, return (true), true);
                        
                        let (suc = sh:qualifiedValueShape(report, sh, vis, s, p, targetList, cstList3)) {
                            if (! suc, set (res = false), true) ;
                            #xt:print("res3:", sh, s, p, res)
                        }
                    } ;
                    
                    if (b4) {
                        # xsh:function [ us:test(term) ]
                        # oper = xsh:function
                        # name = us:test 
                        # value = (term)
                        for ((oper name value ternary) in cstList4) {
                            if (name = sh:display) {
                                funcall(name, s, targetList, value)
                            }
                            else if (oper = xsh:pathFunction) {
                                let (suc = coalesce(funcall(name, s, targetList, value), false)) {
                                    sh:report(report, oper, sh, name, s, p, targetList, suc, vis) ;
                                    if (! suc, set(res = false), true) 
                                }
                            }
                            else {
                                for (o in targetList) {
                                    let (suc = coalesce(
                                        if (ternary, funcall(name, s, o, value), 
                                            funcall(name, o, value)), 
                                            false)) {
                                            sh:report(report, oper, sh, name, s, p, o, suc, vis) ;
                                            if (! suc, set(res = false), true) 
                                    }
                                }
                            }
                        }
                    }
                    
                }
            #}
        };
        
        xt:event("@pathShacl", sh, s, p, cstList1, cstList2, cstList3, cstList4, res);
        return (res)
    }
}



# *******************************************


#
# Retrieve properties of constraint sh using a query, do it once
# they are stored as a list in a map by sh:getConstraint defined in core.rq
#

function sh:getPathShape(shape, sh, shapeList) {
    let (select ?shape ?sh ?shapeList 
    (aggregate (xt:list(?oper, ?arg)) as ?list) 
    where {
            graph ?shape { 
                values ?shapeList {UNDEF}
                values ?oper { unnest(?shapeList) }
                ?sh ?oper ?val 
                optional { ?sh sh:flags ?flag }
                bind (
                    if (?oper = sh:pattern,   coalesce(xt:list(?val, ?flag), xt:list(?val)),
                    if (sh:isListOperator(?oper), sh:getValueList(?val),
                    ?val))
                as ?arg)
                filter if (?oper = sh:uniqueLang, sameTerm(?val, true), true)
            }
        } ) {
        return(list)
    }
}


function sh:optional(shape, sh) { 
    exists { ?sh shex:optional true }
}


function sh:pathextension(shape, sh) {
    sh:getShapeExtension(shape, sh, sh:getShape(sh:pathextension))
}
        
function sh:path1(shape, sh) {
    sh:getPathShape(shape, sh, sh:getShape(sh:path1))
}

function sh:path2(shape, sh) {
    sh:getPathShape(shape, sh, sh:getShape(sh:path2))
}



function sh:lessThan(report, sh, vis, s, p, q, nodeList){
    sh:lessThanList(report, sh, vis, s, p, q, false, sh:lessThan, nodeList)
}

function sh:lessThanOrEquals(report, sh, vis, s, p, q, nodeList){
    sh:lessThanList(report, sh, vis, s, p, q, true, sh:lessThanOrEquals, nodeList)
}

function sh:lessThanList(report, sh, vis, s, p, q, leq, oper, nodeList){
    let (suc = true, targetList = sh:myobjects(s, q)) {
        for (o in nodeList) { 
            for (v in targetList) {
                let (res = coalesce(if (leq, o <= v, o < v), false)) {
                    sh:report(report, oper, sh, s, p, o, res, vis) ;
                    if (! res) {
                        set(suc = false)
                    } 
                }
            }
        } ;
        return (suc)
    }
}

function sh:myobjects2(s, q) {
    xt:objects(s, q)
}

function sh:myobjects(s, q) {
    let (select ?s ?q (aggregate(distinct ?o) as ?list) where { ?s ?q ?o }) {
        return (list)
    }
}


function sh:uniqueLang (report, sh, vis, s, p, v, nodeList){
    let (suc = true, amap = xt:map(),
         nodeLang = mapfindlist(lambda(value) { coalesce(lang(value) != "", false) }, nodeList)) {
         
         for (value in nodeLang) {
            let (lan = lang(value)) {
                xt:set(amap, lan, coalesce(xt:get(amap, lan), 0) + 1)
            }
         } ;
         
         for ((lan value) in amap) {
            let (res = value = 1) {
                if (res, true, set(suc = false));
                sh:report(report, sh:uniqueLang, sh, s, p, lan, res, vis)
            }
         } ;
         
        return (suc)
    }
}



function sh:hasValue (report, sh, vis, s, p, v, nodeList) {
    let (suc = sh:hasValueList(v, nodeList)) {
        sh:report(report, sh:hasValue, sh, s, p, v, suc, vis) ;
        return (suc)
    }
}

function sh:hasValueList (aobject, list) {
    for (value in list) {
        if (coalesce(aobject = value, false), return(true), true)
    } ;
    return (false)
}


function sh:minCount (report, sh, vis, s, p, m, nodeList) {
    let (val = xt:size(nodeList),
         suc = val >= m) { 
        sh:report(report, sh:minCount, sh, s, p, val, suc, vis);
        return(suc)
    }
}

function sh:maxCount (report, sh, vis, s, p, m, nodeList) {
    let (val = xt:size(nodeList),
         suc = val <= m) { 
        sh:report(report, sh:maxCount, sh, s, p, val, suc, vis);
        return(suc)
    }
}





function sh:disjoint (report, sh, vis, s, p, q, nodeList) {
    let (res = true, 
         l1 = nodeList,
         l2 = sh:ppath(s, q)) {
        for (o in l1) {
            let (suc = ! xt:member(o, l2)) {
                sh:report(report, sh:disjoint, sh, s, p, o, suc, vis) ;
                set (res = res && suc)
            }
        } ;
        return (res)
    }
}



function sh:equals (report, sh, vis, s, p, q, nodeList) {
    let (l1 = nodeList, 
         l2 = sh:ppath(s, q)) {         
         let (b1 = sh:myequals (report, sh, vis, s, p, q, l1, l2),
              b2 = sh:myequals (report, sh, vis, s, p, q, l2, l1)) {
        return (b1 && b2)
        }
    }
}

function sh:myequals (report, sh, vis, s, p, q, l1, l2) {
    let (res = true) {
        for (o in l1) {
            let (suc = xt:member(o, l2)) {
                 sh:report(report, sh:equals, sh, s, p, o, suc, vis) ;
                 set(res = res && suc) 
            }
        } ;
        return (res)
    }
}




#
# Boolean operators 
#

function sh:not (report, sh, vis, s, p, cst, nodeList, present) {
    let (res = true) {
        for (o in nodeList) {
            let (suc = ! sh:core(report, cst, false, xt:list(o), present )) { 
                sh:report(report, sh:not, sh, s, p, o, suc, vis);
                set (res = res && suc)
            }
        } ;
        return (res)
    }
}

#
# oper in sh:not sh:and sh:or sh:xone
# basic sh:and sh:or sh:xone defined in core.rq
# cst is the bnode start list of shapes of boolean shape sh
# sh sh:and cst where cst = (sh1 .. shn)
#

function sh:pathbool (report, oper, sh, vis, s, p, cst, nodeList, present) {
    if (oper = sh:not) {
        sh:not (report, sh, vis, s, p, cst, nodeList, present)
    }
    else {
        let (res = true, shList = sh:getShapeConstraint(sh:pathboolean,  cst)) {
            for (o in nodeList) {
                let (suc = coalesce(funcall(oper, report, sh, cst, shList, s, p, o, vis, present), false)) { 
                    #if (suc, true, sh:report(report, oper, sh, s, p, o, suc, vis));
                    set (res = res && suc)
                }
            };
            return (res)
        }
    }
}


#
# cst is the bnode start of the list of shapes of the boolean operator
# and (sh1 .. shn) ; cst = (sh1 .. shn)
# Return the list of shapes of the boolean operator
#
function sh:pathboolean(shape, cst) {
     let ( 
        SELECT ?cst  ?shape (aggregate(?sh) as ?list)
		WHERE {
            graph ?shape { 
                ?cst rdf:rest*/rdf:first ?sh
            } } ) { 
            return (list)
        }
}

















© 2015 - 2025 Weber Informatics LLC | Privacy Policy