def end_class(self, cls: ClassDefinition) -> None: if cls.is_a: self._add_constraint(self.namespaces.uri_for(camelcase(cls.is_a) + "_t")) for mixin in cls.mixins: if self._class_has_expressions(mixin): self._add_constraint(self.namespaces.uri_for(camelcase(mixin) + "_t")) if cls.name in self.synopsis.applytorefs: for applyto in self.synopsis.applytorefs[cls.name].classrefs: if self._class_has_expressions(applyto): self._add_constraint(self.namespaces.uri_for(camelcase(applyto) + '_t')) self.shape.closed = True self.shape.extra = [RDF.type] if self.shape.expression: # TODO: Figure out how to label a single triple expression if isinstance_(self.shape.expression, tripleExprLabel): self.shape.expression = EachOf(expressions=[self.shape.expression, wildcard(None)]) self.shape.expression.id = self.namespaces.uri_for(camelcase(cls.name) + "_t") else: self.shape.expression = wildcard(self.namespaces.uri_for(camelcase(cls.name) + "_t")) if self.class_identifier(cls): self.shape.extra = [RDF.type] type_constraint = TripleConstraint() type_constraint.predicate = RDF.type type_constraint.valueExpr = NodeConstraint(values=[IRIREF(self.namespaces.uri_for(cls.class_uri))]) if not self.shape.expression: self.shape.expression = type_constraint else: self.shape.expression = EachOf(expressions=[self.shape.expression, type_constraint]) shapeExpr = self.shape shapeExpr.id = self._shape_iri(cls.name) self.shapes.append(shapeExpr)
def gen_multivalued_slot(self, target_name_base: str, target_type: IRIREF) -> IRIREF: """ Generate a shape that represents an RDF list of target_type @param target_name_base: @param target_type: @return: """ list_shape_id = IRIREF(target_name_base + "__List") if list_shape_id not in self.list_shapes: list_shape = Shape(id=list_shape_id, closed=True) list_shape.expression = EachOf() expressions = [ TripleConstraint(predicate=RDF.first, valueExpr=target_type, min=0, max=1) ] targets = ShapeOr() targets.shapeExprs = [(NodeConstraint(values=[RDF.nil])), list_shape_id] expressions.append( TripleConstraint(predicate=RDF.rest, valueExpr=targets)) list_shape.expression.expressions = expressions self.shapes.append(list_shape) self.list_shapes.append(list_shape_id) return list_shape_id
def matchesTripleConstraint(cntxt: Context, t: RDFTriple, expr: ShExJ.TripleConstraint, c: DebugContext) -> bool: """ expr is a TripleConstraint and: * t is a triple * t's predicate equals expr's predicate. Let value be t's subject if inverse is true, else t's object. * if inverse is true, t is in arcsIn, else t is in arcsOut. """ from pyshex.shape_expressions_language.p5_3_shape_expressions import satisfies if c.debug: print(c.i(1, " triple: " + t)) print(c.i(1, '', expr._as_json_dumps().split('\n'))) if uriref_matches_iriref(t.p, expr.predicate): value = t.s if expr.inverse else t.o return expr.valueExpr is None or satisfies(cntxt, value, expr.valueExpr) else: cntxt.fail_reason = "Predicate mismatch: " + t.p + " ≠ " + expr.predicate return False
def end_class(self, cls: ClassDefinition) -> None: # On entry self.shape contains all of the triple expressions that define the body of the shape # Finish off the shape definition itself # If there is nothing yet, we're at the very root of things. Add in a final catch-all for any additional # type arcs. NOTE: Here is where you can sink other things as well if you want to ignore categories of things if self.shape.expression is None: self._add_constraint(TripleConstraint(predicate=RDF.type, min=0, max=-1)) self.shape.expression.id = self._class_or_type_uri(cls, '_tes') self.shape.expression = EachOf(expressions=[self.shape.expression, self._type_arc(cls.class_uri, not bool(self.class_identifier(cls)))]) self.shape.closed = not (cls.abstract or cls.mixin) # If this class has subtypes, define the class as the union of its subtypes and itself (if not abstract) if cls.name in self.synopsis.isarefs: childrenExprs = [] for child_classname in sorted(list(self.synopsis.isarefs[cls.name].classrefs)): childrenExprs.append(self._class_or_type_uri(child_classname)) if not (cls.mixin or cls.abstract) or len(childrenExprs) == 1: childrenExprs.insert(0, self.shape) self.shapes.append(ShapeOr(id=self._class_or_type_uri(cls), shapeExprs=childrenExprs)) else: self.shapes.append(ShapeOr(id=self._class_or_type_uri(cls), shapeExprs=childrenExprs)) self.shape.id = self._class_or_type_uri(cls, "_struct") self.shapes.append(self.shape) else: self.shape.id = self._class_or_type_uri(cls) self.shapes.append(self.shape)
def wildcard(id: str) -> TripleConstraint: """ Return a synthetic 'wild card' constraint of the form {p .?} :param id: Triple identifier :return: Corresponding constraint """ return TripleConstraint(id=id, predicate="http://ex.org/dummy", min=0, max=1)
def _type_arc(self, target: URIorCURIE, opt: bool = False) -> TripleConstraint: return TripleConstraint( predicate=RDF.type, valueExpr=NodeConstraint( values=[IRIREF(self.namespaces.uri_for(target))]), min=0 if opt else 1)
def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str, slot: SlotDefinition) -> None: constraint = TripleConstraint() # Juggling to get the constraint to be either a single triple constraint or an eachof construct if not self.shape.expression: self.shape.expression = constraint elif isinstance(self.shape.expression, TripleConstraint): self.shape.expression = EachOf( expressions=[self.shape.expression, constraint]) else: self.shape.expression.expressions.append(constraint) constraint.predicate = self._predicate(slot.name) # JSON-LD generates multi-valued entries as lists constraint.min = 1 if slot.primary_key or slot.required else 0 constraint.max = 1 if not slot.multivalued or self.collections else -1 # TODO: This should not be hard coded -- figure out where to go with it rng = IRIREF(META.SlotRangeTypes) if slot.range == 'anytype' else\ self._type_constraint(slot.range) if slot.range and slot.range not in self.schema.classes else\ self._shapeIRI(slot.range) name_base = ("XSD_" + self.grounded_slot_range(slot.range)) if isinstance( rng, NodeConstraint) else str(rng) constraint.valueExpr = self.gen_multivalued_slot(name_base, rng) \ if slot.multivalued and self.collections else rng
def visitUnaryTripleExpr(self, ctx: ShExDocParser.UnaryTripleExprContext): """ unaryTripleExpr: ('$' tripleExprLabel)? (tripleConstraint | bracketedTripleExpr) | include """ if ctx.include(): self.expression = self.context.tripleexprlabel_to_iriref( ctx.include().tripleExprLabel()) else: lbl = self.context.tripleexprlabel_to_iriref( ctx.tripleExprLabel()) if ctx.tripleExprLabel() else None if ctx.tripleConstraint(): self.expression = TripleConstraint(lbl) self.visit(ctx.tripleConstraint()) elif ctx.bracketedTripleExpr(): self.visit(ctx.bracketedTripleExpr()) self.expression.id = lbl
def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: SlotDefinitionName, slot: SlotDefinition) \ -> None: if not (slot.identifier or slot.abstract or slot.mixin): constraint = TripleConstraint() self._add_constraint(constraint) constraint.predicate = self.namespaces.uri_for(slot.slot_uri) constraint.min = int(bool(slot.required)) constraint.max = 1 if not slot.multivalued else -1 constraint.valueExpr = self._class_or_type_uri(slot.range)
def nevermatch() -> TripleConstraint: """ Return a triple constraint that can never be matched """ return TripleConstraint(predicate="http://ex.org/dummy", min=1, max=1)