def show_unary_op(node, args=None): """ Show the 'unary_op' view of the 'soft' category. """ INFO("soft.show_unary_op(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?operator ?operand WHERE { %s expr:hasOperator ?operator . %s expr:hasOperand ?operand . } """ % ((node["qname"], ) * 2)) if len(results) == 0: raise Exception( "Invalid specification of unary operation %s.\n\nNode=%s" % (node["qname"], pprint.pformat(node))) for (operatorUri, operandUri) in results: operatorNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(operatorUri)) operandNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(operandUri)) node["operator"] = operatorNode["qname"] node["operand"] = operandNode["qname"] operatorNode.show("soft") operandNode.show("soft")
def getMemberPath(startUri, endUri): """ Get the path to a member.. """ INFO("soft.getMemberPath(%s,%s)" % (startUri, endUri)) startUri = str(startUri) endUri = str(endUri) if startUri == endUri: return [] else: results = QUERY(""" SELECT DISTINCT ?member ?label WHERE { <%s> soft:hasVariable ?member . ?member (soft:hasVariable)* <%s> . OPTIONAL { <%s> rdfs:label ?label . } } """ % (startUri, endUri, startUri)) if len(results) == 0: raise Exception("%s has no member that owns %s!" % (startUri, endUri)) for (memberUri, label) in results: if label is None: raise Exception("%s has no label!" % (startUri)) return [label.toPython()] + getMemberPath(str(memberUri), endUri)
def getDefaultNode(cache, qname): """ Get a Node with default information, or get the node from the cache if available. The default information of a node includes: - its qname - its label - its uri - its comment - its ontoscript counter - its RDF classes (a list of qnames) All nodes contain the default information + optional other slots (filled by the show_... callbacks mentioned in allviews.py) + optional expansions (filled by the get... callbacks mentioned in allviews.py) """ try: node = cache[qname] except: INFO(" Get default node for %s" %qname) results = QUERY(""" SELECT DISTINCT ?label ?comment ?counter ?rdfClass WHERE { OPTIONAL { %s rdfs:label ?label } . OPTIONAL { %s rdfs:comment ?comment } . OPTIONAL { %s ontoscript:counter ?counter } . OPTIONAL { %s a/(rdfs:subClassOf*) ?rdfClass . FILTER (!isBlank(?rdfClass)) } . } """ %(qname,qname,qname,qname)) node = Node( qname = qname, uri = QNAME_TO_URI(qname), cache = cache) rdfClasses = [] # only for logging for label, comment, counter, rdfClass in results: if label is not None: node["label"] = label.toPython() if comment is not None: node["comment"] = comment.toPython() if counter is not None: node["counter"] = int(counter.toPython()) if rdfClass is not None: rdfClassQName = URI_TO_QNAME(rdfClass) node.registerClass(rdfClassQName) rdfClasses.append(rdfClassQName) INFO(" --> label '%s', counter %d, rdfClasses %s" %(node["label"], node["counter"], rdfClasses)) node.registerClass("rdfs:Resource") node.registerKnownViews() cache[qname] = node return node
def show_binary_op(node, args=None): """ Show the 'binary_op' view of the 'soft' category. """ INFO("soft.show_binary_op(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?operator ?left ?right WHERE { %s expr:hasOperator ?operator . %s expr:hasLeftOperand ?left . %s expr:hasRightOperand ?right . } """ % ((node["qname"], ) * 3)) if len(results) == 0: raise Exception( "Invalid specification of binary operation %s.\n\nNode=%s" % (node["qname"], pprint.pformat(node))) for (operatorUri, leftUri, rightUri) in results: oNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(operatorUri)) lNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(leftUri)) rNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(rightUri)) node["operator"] = oNode["qname"] node["left"] = lNode["qname"] node["right"] = rNode["qname"] oNode.show("soft") lNode.show("soft") rNode.show("soft")
def isPlcEnum(type): """ Ask if the given type is an IEC 61131-3 enum """ result = QUERY(""" ASK WHERE { %s rdf:type/rdfs:subClassOf* iec61131:Enum . } """ % type) return bool(result)
def isPlcStruct(type): """ Ask if the given type is an IEC 61131-3 struct """ result = QUERY(""" ASK WHERE { %s rdf:type/rdfs:subClassOf* iec61131:Struct . } """ % type) return bool(result)
def isPlcFb(type): """ Ask if the given type is an IEC 61131-3 function block """ result = QUERY(""" ASK WHERE { %s rdf:type/rdfs:subClassOf* iec61131:FunctionBlock . } """ % type) return bool(result)
def show_variable(node, args=None): """ Show the 'variable' view of the 'soft' category. """ INFO("soft.show_variable(%s)" % node['qname']) node["type"] = None node["points_to_type"] = None node["initial_value"] = None node["address"] = None node["value"] = None results = QUERY(""" SELECT DISTINCT ?type ?pointsToType ?initialValue ?address ?link ?value WHERE { OPTIONAL { %s soft:hasType | (^soft:isTypeOf) ?type . } . OPTIONAL { %s soft:pointsToType ?pointsToType .} . OPTIONAL { %s soft:hasInitialValue ?initialValue . } . OPTIONAL { %s soft:hasAddress ?address . } . OPTIONAL { %s expr:hasValue | expr:hasNumericValue ?value . } . } """ % ((node["qname"], ) * 5)) for type, pointsToType, initialValue, address, link, value in results: if type is not None: typeQName = URI_TO_QNAME(type.toPython()) node["type"] = typeQName generic.getDefaultNode(node.cache, typeQName).show("soft", "type") if pointsToType is not None: pointsToTypeQName = URI_TO_QNAME(pointsToType.toPython()) node["points_to_type"] = pointsToTypeQName generic.getDefaultNode(node.cache, pointsToTypeQName).show("soft", "type") if initialValue is not None: node["initial_value"] = initialValue.toPython() if address is not None: node["address"] = address.toPython() if value is not None: node["value"] = getExpressionString(value) node.expand("soft", "variable") for memberOf in node["member_of"]: node.cache[memberOf].show("soft") for l in node["links"]: node.cache[l].show("soft") for qualifier in node["qualifiers"]: node.cache[qualifier].show("soft")
def getAllConstraintViolations(): """ Get a list of all constraint violations. @return: a list of dictionaries. """ results = QUERY(""" SELECT DISTINCT ?root ?rootLabel ?rootCounter ?value ?level ?label WHERE { ?violation rdf:type/rdfs:subClassOf* spin:ConstraintViolation . ?violation spin:violationRoot ?root . ?root rdfs:label ?rootLabel . OPTIONAL { ?root ontoscript:counter ?rootCounter } . OPTIONAL { ?violation spin:violationValue ?value } . OPTIONAL { ?violation spin:violationLevel ?level } . ?violation rdfs:label ?label . } """) d = {} for rootUri, rootLabel, rootCounter, value, level, label in results: root = URI_TO_QNAME(rootUri) hash = "%s-%s" % (root, label) if hash not in d.keys(): d[hash] = { "root": { "uri": rootUri.toPython(), "qname": root, "counter": -1, "label": rootLabel.toPython() }, "label": label.toPython(), "value": value, "level": level } if rootCounter is not None: d[hash]["root"]["counter"] = int(rootCounter.toPython()) if value is not None: try: d[hash]["value"] = value.toPython() except: pass if level is not None: try: d[hash]["level"] = level.toPython() except: pass return sorted(d.values(), key=lambda x: x["root"]["counter"])
def getCommonVariablesOfContext(variableUri, contextUri): """ Get the common variables of a given variable and a given context. """ INFO("soft.getCommonVariablesOfContext(%s,%s)" % (variableUri, contextUri)) ret = [] results = QUERY(""" SELECT DISTINCT ?member WHERE { <%s> soft:hasVariable ?member . ?member (soft:hasVariable)* <%s> . } """ % (contextUri, variableUri)) for (member, ) in results: ret.append(member.toPython()) return ret
def show_browse(node, args=None): """ Show the 'browse' view of the 'browse' category. """ INFO("browse.show_browse(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?predicate ?object WHERE { %s ?predicate ?object . } """ % node["qname"]) d = {} for predicateUri, ob in results: predicate = URI_TO_QNAME(predicateUri) if type(ob) == rdflib.term.URIRef: object = { "type": "uri", "content": { "uri": ob.toPython(), "qname": URI_TO_QNAME(ob) } } elif type(ob) == rdflib.term.BNode: object = {"type": "bnode", "content": {"id": ob}} elif type(ob) == rdflib.term.Literal: object = {"type": "literal", "content": ob.toPython()} else: object = {"type": "unknown", "content": ob} if predicate not in d.keys(): d[predicate] = { "uri": predicateUri, "qname": predicate, "objects": [object] } else: d[predicate]["objects"].append(object) node["results"] = sorted(d.values(), key=lambda x: x["qname"])
def show_primitive(node, args=None): """ Show the 'primitive' view of the 'soft' category. """ INFO("soft.show_InterfaceInstance(%s)" % node['qname']) # extra query to get the string value or numeric value results = QUERY(""" SELECT DISTINCT ?value WHERE { %s expr:hasValue|expr:hasNumericValue ?value . } """ % node["qname"]) node["value"] = None for (value, ) in results: if value is not None: node["value"] = getExpressionString(value)
def show_operator(node, args=None): """ Show the 'operator' view of the 'soft' category. """ INFO("soft.show_operator(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?symbol WHERE { OPTIONAL { %s iec61131:hasSymbol ?symbol . } . } """ % ((node["qname"], ) * 1)) node["plc_symbol"] = None for (symbol, ) in results: if symbol is not None: node["plc_symbol"] = symbol.toPython()
def fillNumber(node, optional=False): """ Fill out the number of a container item (according to the containers ontology). """ INFO(" Fill number of %s") node["number"] = None results = QUERY(""" SELECT DISTINCT ?number WHERE { %s (cont:isItemOf|(^cont:hasItem))/cont:hasNumber ?number . } """ %node["qname"]) for (number,) in results: node["number"] = int(number.toPython()) INFO(" --> %s" %node["number"])
def show_type(node, args=None): """ Show the 'type' view of the 'soft' category. """ INFO("soft.show_type(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?implementation ?symbol ?extends ?returnType WHERE { OPTIONAL { %s soft:hasImplementation ?implementation . } . OPTIONAL { ?implementation soft:isImplementationOf %s . } . OPTIONAL { %s (^owl:sameAs)/iec61131:hasSymbol | iec61131:hasSymbol ?symbol . } . OPTIONAL { %s soft:extends ?extends } . OPTIONAL { %s soft:hasReturnType ?returnType . } . } """ % ((node["qname"], ) * 5)) node["implementation"] = None node["plc_symbol"] = None node["extends"] = None node["returnType"] = None for implementation, symbol, extends, returnType in results: if implementation is not None: implementationQName = URI_TO_QNAME(implementation.toPython()) node["implementation"] = implementationQName generic.getDefaultNode(node.cache, implementationQName) # don't show it here if symbol is not None: node["plc_symbol"] = symbol.toPython() if extends is not None: extendsQName = URI_TO_QNAME(extends.toPython()) node["extends"] = extendsQName generic.getDefaultNode(node.cache, extendsQName).show("soft") if returnType is not None: returnTypeQName = URI_TO_QNAME(returnType.toPython()) node["returnType"] = returnTypeQName generic.getDefaultNode(node.cache, returnTypeQName).show("soft")
def getEnumPath(variableUri): """ Get the path to an enumeration. """ INFO("soft.getEnumPath(%s)" % (variableUri)) results = QUERY(""" SELECT DISTINCT ?enum ?label WHERE { ?enum soft:hasEnumerationItem <%s> . ?enum rdfs:label ?label . } """ % (variableUri)) if len(results) == 0: return None elif len(results) > 1: raise Exception("Multiple enum definitions were found for item %s!" % variableUri) else: for (enumUri, enumLabel) in results: return {"path": [enumLabel.toPython()]}
def show_if_then(node, args=None): """ Show the 'if_then' view of the 'soft' category. """ INFO("soft.show_if_then(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?if ?then ?else WHERE { %s soft:if ?if . %s soft:then ?then . OPTIONAL { %s soft:else ?else . } } """ % ((node["qname"], ) * 3)) if len(results) != 1: raise Exception("Invalid specification of IfThen operation %s" % node["qname"]) node["if"] = None node["then"] = None node["else"] = None for (i, t, e) in results: iNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(i)) tNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(t)) node["if"] = iNode["qname"] node["then"] = tNode["qname"] iNode.show("soft") tNode.show("soft") if e is not None: eNode = generic.getDefaultNode(node.cache, URI_TO_QNAME(e)) node["else"] = eNode["qname"] eNode.show("soft")
def show_qualifier(node, args=None): """ Show the 'qualifier' view of the 'soft' category. """ INFO("soft.show_qualifier(%s)" % node['qname']) results = QUERY(""" SELECT DISTINCT ?symbol ?value WHERE { OPTIONAL { %s iec61131:hasSymbol ?symbol . } . OPTIONAL { %s expr:hasValue ?value . } . } """ % ((node["qname"], ) * 2)) node["plc_symbol"] = None node["value"] = None for symbol, value in results: if symbol is not None: node["plc_symbol"] = symbol.toPython() if value is not None: node["value"] = value.toPython()
def getInstances(cache, className, filterNotExists=None): """ Get the instances of a class. """ INFO(" Get instances of %s" %className) if filterNotExists is None: filterNotExistsLine = "" else: filterNotExistsLine = "FILTER NOT EXISTS { %s }" %filterNotExists results = QUERY(""" SELECT DISTINCT ?instance ?label ?comment ?counter ?rdfClass WHERE { ?instance rdf:type/rdfs:subClassOf* %s . OPTIONAL { ?instance rdfs:label ?label } . OPTIONAL { ?instance rdfs:comment ?comment } . OPTIONAL { ?instance ontoscript:counter ?counter } . OPTIONAL { ?instance a/(rdfs:subClassOf*) ?rdfClass . FILTER (!isBlank(?rdfClass)) } . %s } """ %(className, filterNotExistsLine)) d = {} for uri, label, comment, counter, rdfClass in results: qname = URI_TO_QNAME(uri) if not d.has_key(qname): d[qname] = Node( qname = qname, uri = uri.toPython(), cache = cache) if label is not None: d[qname]["label"] = label.toPython() if comment is not None: d[qname]["comment"] = comment.toPython() if counter is not None: d[qname]["counter"] = int(counter.toPython()) if rdfClass is not None: d[qname].registerClass(URI_TO_QNAME(rdfClass.toPython())) keysStr = "" for key in d.keys(): keysStr += (key + " ") INFO(" --> " + keysStr) for qname, node in d.items(): node.registerKnownViews() if not cache.has_key(qname): DEBUG("Caching %s" %qname) cache[qname] = node # return a list of QNames ret = [] # list of qnames resultNodes = sorted(d.values(), key=lambda x: x["counter"]) for resultNode in resultNodes: ret.append(resultNode['qname']) return ret
def fillFields(node, mandatories={}, optionals={}): """ Fill some mandatory and/or optional fields of a node. """ subject = node['qname'] INFO(" Fill these fields of %s: mandatories=%s, optionals=%s" %(subject, mandatories.keys(), optionals.keys())) selectLine = "" wherePart = "" for key,value in mandatories.items(): selectLine += " ?%s" %key wherePart += "%s %s ?%s .\n" %(subject, value, key) for key,value in optionals.items(): selectLine += " ?%s" %key wherePart += "OPTIONAL { %s %s ?%s } .\n" %(subject, value, key) query = """ SELECT DISTINCT %s WHERE { %s } """ %(selectLine, wherePart) results = QUERY(query) if len(results) == 0: raise Exception("No results for query:\n%s" %query) infoStr = " --> mandatories [" for result in results: # the mandatories for i in xrange(len(mandatories)): key = mandatories.keys()[i] try: if IS_URI(result[i]): node.cache[subject][key] = URI_TO_QNAME(result[i].toPython()) else: node.cache[subject][key] = result[i].toPython() except: node.cache[subject][key] = None if i > 0: infoStr += "," infoStr += str(node.cache[subject][key]) infoStr += "], optionals [" for i in xrange(len(optionals)): key = optionals.keys()[i] try: j = len(mandatories) + i if IS_URI(result[j]): node.cache[subject][key] = URI_TO_QNAME(result[j].toPython()) else: node.cache[subject][key] = result[j].toPython() except: node.cache[subject][key] = None if i > 0: infoStr += "," infoStr += str(node.cache[subject][key]) infoStr += "]" INFO(infoStr)
def getRelated(cache, subject, property, restriction=None, remove=None, sortedByNumber=False, filterNotExists=None): """ Get the related individuals of an individual. """ INFO(" Get related %s of %s" %(property, subject)) extraVariables = "" if restriction is None: restrictionLine = "" else: restrictionLine = "\n ?result rdf:type/rdfs:subClassOf* %s ." %restriction if remove is None: removeLine = "" else: removeLine = "\n FILTER NOT EXISTS { %s %s ?result }" %(subject, remove) if sortedByNumber: numberLine = "\n OPTIONAL { ?result (cont:isItemOf|(^sys:hasItem))/cont:hasNumber ?number }" extraVariables += "?number" else: numberLine = "" if filterNotExists is None: filterNotExistsLine = "" else: filterNotExistsLine = "FILTER NOT EXISTS { %s }" %filterNotExists results = QUERY(""" SELECT DISTINCT ?result ?label ?comment ?counter ?rdfClass %s WHERE { %s %s ?result . %s%s%s OPTIONAL { ?result rdfs:label ?label } . OPTIONAL { ?result rdfs:comment ?comment } . OPTIONAL { ?result ontoscript:counter ?counter } . OPTIONAL { ?result a/(rdfs:subClassOf*) ?rdfClass . FILTER (!isBlank(?rdfClass)) } . %s } """ %(extraVariables, subject, property, restrictionLine, removeLine, numberLine, filterNotExistsLine)) d = {} for result in results: resultQName = URI_TO_QNAME(result[0]) if resultQName not in d.keys(): d[resultQName] = Node(uri = result[0].toPython(), qname = resultQName, cache = cache) if result[1] is not None: d[resultQName]["label"] = result[1].toPython() if result[2] is not None: d[resultQName]["comment"] = result[2].toPython() if result[3] is not None: d[resultQName]["counter"] = int(result[3].toPython()) if result[4] is not None: d[resultQName].registerClass(URI_TO_QNAME(result[4].toPython())) if sortedByNumber: if result[5] is not None: d[resultQName]["number"] = int(result[5].toPython()) else: d[resultQName]["number"] = None keysStr = "" for key in d.keys(): keysStr += (key + " ") INFO(" --> " + keysStr) for resultQName, resultNode in d.items(): resultNode.registerKnownViews() if not cache.has_key(resultQName): cache[resultQName] = d[resultQName] # return a list of QNames ret = [] # list of qnames # first sort by 'counter' key: resultNodes = sorted(d.values(), key=lambda x: x['counter']) # entries with None will be put first in the sorted list # then, if necessary, sort by number: if sortedByNumber: resultNodes = sorted(resultNodes, key=lambda x: x['number']) for resultNode in resultNodes: ret.append(resultNode['qname']) return ret