def gather_rules(shacl_graph): """ :param shacl_graph: :type shacl_graph: ShapesGraph :return: :rtype: [SHACLRule] """ triple_rule_nodes = set(shacl_graph.subjects(RDF_type, SH_TripleRule)) sparql_rule_nodes = set(shacl_graph.subjects(RDF_type, SH_SPARQLRule)) overlaps = triple_rule_nodes.intersection(sparql_rule_nodes) if len(overlaps) > 0: raise RuleLoadError( "A SHACL Rule cannot be both a TripleRule and a SPARQLRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax") used_rules = shacl_graph.subject_objects(SH_rule) ret_rules = defaultdict(list) for sub, obj in used_rules: try: shape = shacl_graph.lookup_shape_from_node(sub) except (AttributeError, KeyError): raise RuleLoadError( "The shape that rule is attached to is not a valid SHACL Shape.", "https://www.w3.org/TR/shacl-af/#rules-syntax") if obj in triple_rule_nodes: rule = TripleRule(shape, obj) elif obj in sparql_rule_nodes: rule = SPARQLRule(shape, obj) else: raise RuleLoadError( "when using sh:rule, the Rule must be defined as either a TripleRule or SPARQLRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax") ret_rules[shape].append(rule) return ret_rules
def __init__(self, shape: 'Shape', rule_node: 'rdflib.term.Identifier', **kwargs): """ :param shape: :type shape: Shape :param rule_node: :type rule_node: rdflib.term.Identifier """ super(SPARQLRule, self).__init__(shape, rule_node, **kwargs) construct_nodes = set(self.shape.sg.objects(self.node, SH_construct)) if len(construct_nodes) < 1: raise RuleLoadError("No sh:construct on SPARQLRule", "https://www.w3.org/TR/shacl-af/#SPARQLRule") self._constructs = [] for c in construct_nodes: if not isinstance(c, Literal) or not ( c.datatype == XSD_string or c.language is not None or isinstance(c.value, str) ): raise RuleLoadError( "SPARQLRule sh:construct must be an xsd:string", "https://www.w3.org/TR/shacl-af/#SPARQLRule" ) self._constructs.append(str(c.value)) SPARQLQueryHelper = get_query_helper_cls() query_helper = SPARQLQueryHelper(self.shape, self.node, None, deactivated=self._deactivated) query_helper.collect_prefixes() self._qh = query_helper
def get_conditions(self): cond_nodes = list(self.shape.sg.graph.objects(self.node, SH_condition)) conditions = [] for c in cond_nodes: # check if this is a rdf:list test_me = list(self.shape.sg.graph.predicate_objects(c)) first_nodes = list(self.shape.sg.graph.objects(c, RDF_first)) if len(first_nodes) > 0: for c_item in self.shape.sg.graph.items(c): try: cond_shape = self.shape.sg.lookup_shape_from_node(c_item) except (AttributeError, KeyError): raise RuleLoadError( "A SHACL Rule Condition must be an existing well-formed SHACL Shape.", "https://www.w3.org/TR/shacl-af/#condition") condition = SHACLRuleCondition(self, cond_shape) conditions.append(condition) else: try: cond_shape = self.shape.sg.lookup_shape_from_node(c) except (AttributeError, KeyError): raise RuleLoadError( "A SHACL Rule Condition must be an existing well-formed SHACL Shape.", "https://www.w3.org/TR/shacl-af/#condition") condition = SHACLRuleCondition(self, cond_shape) conditions.append(condition) return conditions
def gather_rules( shacl_graph: 'ShapesGraph') -> Dict['Shape', List['SHACLRule']]: """ :param shacl_graph: :type shacl_graph: ShapesGraph :return: :rtype: Dict[Shape, List[SHACLRule]] """ triple_rule_nodes = set(shacl_graph.subjects(RDF_type, SH_TripleRule)) sparql_rule_nodes = set(shacl_graph.subjects(RDF_type, SH_SPARQLRule)) if shacl_graph.js_enabled: from pyshacl.extras.js.rules import JSRule, SH_JSRule js_rule_nodes = set(shacl_graph.subjects(RDF_type, SH_JSRule)) use_JSRule: Union[bool, Type] = JSRule else: use_JSRule = False js_rule_nodes = set() overlaps = triple_rule_nodes.intersection(sparql_rule_nodes) if len(overlaps) > 0: raise RuleLoadError( "A SHACL Rule cannot be both a TripleRule and a SPARQLRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax", ) overlaps = triple_rule_nodes.intersection(js_rule_nodes) if len(overlaps) > 0: raise RuleLoadError( "A SHACL Rule cannot be both a TripleRule and a JSRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax", ) overlaps = sparql_rule_nodes.intersection(js_rule_nodes) if len(overlaps) > 0: raise RuleLoadError( "A SHACL Rule cannot be both a SPARQLRule and a JSRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax", ) used_rules = shacl_graph.subject_objects(SH_rule) ret_rules = defaultdict(list) for sub, obj in used_rules: try: shape: Shape = shacl_graph.lookup_shape_from_node(sub) except (AttributeError, KeyError): raise RuleLoadError( "The shape that rule is attached to is not a valid SHACL Shape.", "https://www.w3.org/TR/shacl-af/#rules-syntax", ) if obj in triple_rule_nodes: rule: SHACLRule = TripleRule(shape, obj) elif obj in sparql_rule_nodes: rule = SPARQLRule(shape, obj) elif use_JSRule and callable(use_JSRule) and obj in js_rule_nodes: rule = use_JSRule(shape, obj) else: raise RuleLoadError( "when using sh:rule, the Rule must be defined as either a TripleRule or SPARQLRule.", "https://www.w3.org/TR/shacl-af/#rules-syntax", ) ret_rules[shape].append(rule) return ret_rules
def order(self): order_nodes = list(self.shape.sg.objects(self.node, SH_order)) if len(order_nodes) < 1: return Decimal("0.0") if len(order_nodes) > 1: raise RuleLoadError( "A SHACL Rule can have only one sh:order property.", "https://www.w3.org/TR/shacl-af/#rules-order") order_node = next(iter(order_nodes)) if not isinstance(order_node, Literal): raise RuleLoadError("A SHACL Rule must be a numeric literal.", "https://www.w3.org/TR/shacl-af/#rules-order") return Decimal(order_node.value)