class ShExSchema: """ ShEx XML Schema to JSON wrapper """ def __init__(self, dom_schema): """ Constructor - convert the supplied schema to json :param dom_schema: DOM document to convert """ self.schema = CreateFromDOM(dom_schema) self.json = dict(type="schema") self._prefixmap = PrefixMap(self.schema, dom_schema) self._exclude_prefixes = self.schema.exclude_prefixes.split(' ') + ['xml', 'xmlns'] self.shex_schema() def shex_schema(self): """ <code>xs:Element name="Schema" type="shex:Schema</code> """ self.json["prefixes"] = {prefix: url for prefix, url in self._prefixmap.namespaces().items() if prefix is not None and url and prefix not in self._exclude_prefixes} if self.schema.startActions: self.json["startActs"] = self.shex_semantic_actions(self.schema.startActions) if self.schema.shape: self.json["shapes"] = {self._uri(s.label): self.shex_shape(s) for s in self.schema.shape} if self.schema.valueClass: self.json["valueClasses"] = \ {self.shex_iri(vc.definition.valueClassLabel if vc.definition else vc.external.ref): self.shex_value_class_definition(vc) for vc in self.schema.valueClass} if self.schema.start: self.json["start"] = self._uri(self.schema.start) def shex_shape(self, shape: Shape) -> dict: """ <code>xs:complexType name="shape"</code> :param shape: XML Shape :return: S-JSON Shape Entry """ rval = dict(type="shape") w_shape = PyxbWrapper(shape) self.shex_annotations_and_actions(rval, w_shape) [self.shex_expression_choice(rval, e) for e in w_shape.elements] for e in w_shape.elements: if e.type == "import_": rval.setdefault("inherit", []).append(self.shex_shape_ref(e.value.node)) elif e.type == "extra": rval.setdefault(e.type, []).append(self._uri(e.value.node.ref)) # shape.label is the dictionary key in the Schema container if shape.virtual: rval["virtual"] = shape.virtual if shape.closed: rval["closed"] = shape.closed return rval @staticmethod def _typed_expression(typ: str, val: dict) -> dict: val["type"] = typ return val def shex_expression_choice(self, target: dict, e: PyxbWrapper.PyxbElement) -> dict: """ <code>xs:group name="ExpressionChoice"</code> :param target: target type with ExpressionChoice mixin :param e: Wrapper for ExpressionChoice element :return: target """ if e.type in ["someOf", "group"]: expr = self.shex_shape_constraint(e.value.node) elif e.type == "tripleConstraint": expr = self.shex_triple_constraint(e.value.node) elif e.type == "include": expr = dict(include=self._uri(e.value.node.ref)) else: expr = None if expr: target["expression"] = self._typed_expression(e.type, expr) return target def shex_annotations_and_actions(self, target: dict, ew: PyxbWrapper): """ <code>xs:group name="AnnotationsAndActions</code> :param target: dictionary using the group :param ew: xml element that contains the group """ for e in ew.elements: if e.type == "actions": target["semActs"] = self.shex_semantic_actions(e.value.node) elif e.type == "annotation": target.setdefault("annotations", []).append(self.shex_annotation(e.value.node)) def shex_shape_constraint(self, sc: ShapeConstraint) -> dict: """ <code>xs:complexType name="ShapeConstraint"</code> :param sc: A complete shape constraint :return: S-JSON expression """ rval = dict() sc_wrapper = PyxbWrapper(sc) for e in sc_wrapper.elements: entry = self.shex_expression_choice({}, e) if "expression" in entry: rval.setdefault("expressions", []).append(entry["expression"]) self.shex_annotations_and_actions(rval, sc_wrapper) self.shex_cardinality(rval, sc_wrapper) return rval def shex_triple_constraint(self, tc: TripleConstraint) -> dict: """ <code>xs:complexType name="TripleConstraint"</code> :param tc: TripleConstraint to process :return: SJson equivalent """ assert not ((tc.objectConstraint or tc.object or tc.objectShape or tc.objectType) and (tc.subjectConstraint or tc.subject or tc.subjectShape or tc.subjectType)), \ "Cannot mix subject and object constraints" tc_dict = dict(type="tripleConstraint", predicate=self.shex_iri(tc.predicate)) if tc.valueClass: tc_dict["valueClassRef"] = self.shex_value_class_label(tc.valueClass) else: vc_dict = dict(type="valueClass") if tc.objectConstraint: self.shex_triple_constraint_value_class(vc_dict, tc.objectConstraint) if tc.object: vc_dict["values"] = [self.shex_iri(tc.object)] if tc.objectShape: vc_dict["reference"] = self.shex_shape_label(tc.objectShape) if tc.objectType: vc_dict["nodeKind"] = self.shex_node_type(tc.objectType) if tc.subjectConstraint or tc.subject or tc.subjectShape or tc.subjectType or tc.inverse: tc_dict["inverse"] = True if tc.subjectConstraint: self.shex_triple_constraint_value_class(vc_dict, tc.subjectConstraint) if tc.subject: vc_dict["values"] = [self.shex_iri(tc.subject)] if tc.subjectShape: vc_dict["reference"] = self.shex_shape_label(tc.subjectShape) if tc.subjectType: vc_dict["nodeKind"] = self.shex_node_type(tc.subjectType) if tc.datatype: vc_dict["datatype"] = self._uri(tc.datatype) if tc.negated: tc_dict["negated"] = tc.negated tc_wrapper = PyxbWrapper(tc) self.shex_annotations_and_actions(tc_dict, tc_wrapper) self.shex_cardinality(tc_dict, tc_wrapper) tc_dict["value"] = vc_dict return tc_dict @staticmethod def shex_node_type(nt: NodeType): return str(nt).lower() def shex_annotation(self, annot: Annotation) -> list: """ <code>xs:complexType name="Annotation"</code> :param annot: Annotation :return: S-JSON equivalent """ rval = [self._uri(annot.iri)] if annot.iri else [] if annot.literal: rval.append(self.shex_rdf_literal(annot.literal)) else: rval.append(self.shex_iri_ref(annot.iriref)) return rval def shex_semantic_actions(self, acts: SemanticActions) -> list: """ <code>xs:complexType name="SemanticActions"</code> :param acts: actions :return: list of actions """ return [self.shex_semantic_action(a) for a in acts.action] def shex_semantic_action(self, act: SemanticAction) -> dict: """ <code>xs:complexType name="SemanticAction"</code> :param act: action :return: S-JSON representation """ # TODO: validating rval = {} if act.productionName: rval['name'] = self._uri(act.productionName.ref) if act.codeDecl: rval['contents'] = self.shex_code_decl(act.codeDecl) return rval @staticmethod def shex_code_decl(cd: CodeDecl): """ <code>xs:complexType name="CodeDecl" mixed="true"</code> :param cd: :return: """ return PyxbWrapper.mixed_content(cd) def shex_value_class_definition(self, vcd: ValueClassDefinition) -> dict: """ <code>xs:complexType name="ValueClassDefinition"</code> :param vcd: :return: """ rval = dict(type="valueClass") if vcd.external: rval["external"] = self.shex_value_class_ref(vcd.external) else: self.shex_inline_value_class_definition(rval, vcd.definition) if vcd.definition.actions: rval["semActs"] = self.shex_semantic_actions(vcd.definition.actions) return rval def shex_inline_value_class_definition(self, vc: dict, ivcd: InlineValueClassDefinition) -> list: """ <code>xs:complexType name="InlineValueClassDefinition"</code> :param vc: dictionary to record the actual elements :param ivcd: :return: """ # valueClassLabel becomes the identity vcd_wrapper = PyxbWrapper(ivcd) for e in vcd_wrapper.elements: if e.type == "nodetype": vc["nodeKind"] = self.shex_node_type(e.value.node) elif e.type == "datatype": vc[e.type] = self._uri(e.value.node) elif e.type == "facet": self.shex_xs_facet(vc, e.value.node) elif e.type == "or_": vc["reference"] = self.shex_group_shape_constr(e.value.node) elif e.type == "valueSet": vc["values"] = self.shex_value_set(e.value.node) else: assert False, "Unknown ValueClassExpression choice entry: %s" % e.type def shex_group_shape_constr(self, gsc: GroupShapeConstr) -> dict: """ <code>xs:complexType name="GroupShapeConstr"</code> :param gsc: :return: """ rval = dict(type="or", disjuncts=[self.shex_shape_ref(d) for d in gsc.disjunct]) if gsc.stringFacet: [self.shex_xs_facet(rval, e) for e in gsc.stringFacet] return rval # noinspection PyTypeChecker def shex_triple_constraint_value_class(self, vc: dict, tcvc: TripleConstraintValueClass) -> (dict, dict): return self.shex_inline_value_class_definition(vc, tcvc) def shex_value_class_label(self, l: ValueClassLabel) -> str: """ <code>xs:simpleType name="ValueClassLabel"</code> :param l: :return: """ return self.shex_iri(l) def shex_value_class_ref(self, lr: ValueClassRef) -> str: """ <code>xs:complexType name="ValueClassRef"</code> :param lr: :return: """ return self.shex_value_class_label(lr.ref) def shex_shape_label(self, sl: ShapeLabel) -> str: """ <code>xs:simpleType name="ShapeLabel"</code> :param sl: :return: """ return self.shex_iri(sl) def shex_shape_ref(self, sr: ShapeRef) -> str: """ <code>xs:complexType name="ShapeRef"</code> :param sr: :return: """ return self.shex_shape_label(sr.ref) @staticmethod def shex_code_label(cl: ProductionName) -> str: """ <code>xs:complexType name="CodeLabel"</code> :param cl: :return: """ return cl.ref.value() @staticmethod def _normalize_value(v): return int(v.integer) if v.integer is not None else \ float(v.double) if v.double is not None else float(v.decimal) @staticmethod def shex_xs_facet(target: dict, f: XSFacet): """ <code>xs:complexType name="XSFacet"</code> :param target: target dictionary (ValueClass) :param f: facet to transform """ if f.pattern: target["pattern"] = f.pattern elif f.not_: target["negated"] = True elif f.minLength: target["minlength"] = f.minLength elif f.maxLength: target["maxlength"] = f.maxLength elif f.length: target["length"] = f.length elif f.minValue: if f.minValue.open: target["minexclusive"] = ShExSchema._normalize_value(f.minValue) else: target["mininclusive"] = ShExSchema._normalize_value(f.minValue) elif f.maxValue: if f.maxValue.open: target["maxexclusive"] = ShExSchema._normalize_value(f.maxValue) else: target["maxinclusive"] = ShExSchema._normalize_value(f.maxValue) elif f.totalDigits: target["totaldigits"] = f.totalDigits elif f.fractionDigits: target["fractiondigits"] = f.fractionDigits else: assert False, "Unknown facet %s" % f # shex_endpoint is covered in the xs_facet logic above # noinspection PyTypeChecker @staticmethod def shex_string_facet(target: dict, sf: StringFacet): ShExSchema.shex_xs_facet(target, sf) # noinspection PyTypeChecker @staticmethod def shex_numeric_facet(target: dict, nf: NumericFacet): ShExSchema.shex_xs_facet(target, nf) def shex_value_set(self, vs: ValueSet) -> list: if vs.iriRange: return [self.shex_iri_range(e) for e in vs.iriRange] elif vs.rdfLiteral: return [self.shex_rdf_literal(e) for e in vs.rdfLiteral] elif vs.integer: return ['"%i"^^%s' % (e, XSD.integer) for e in vs.integer] elif vs.decimal: return ['"%d"^^%s' % (e, XSD.decimal) for e in vs.decimal] elif vs.double: return ['"%e"^^%s' % (e, XSD.double) for e in vs.double] elif vs.boolean: return ['"%s"^^%s' % (e, XSD.boolean) for e in vs.boolean] else: assert False, "Unknown ValueSet type" def shex_iri_stem(self, ist: IRIStem) -> dict: if ist.base and not ist.stem: return self.shex_iri(ist.base) else: return dict(stem=self.shex_iri(ist.base)) if ist.base else dict(stem=dict(type="wildcard")) def shex_iri_range(self, irir: IRIRange) -> object: """ :param irir: :return: """ def add_stem_type(d: dict, v: IRIStem): if v.stem: d["type"] = "stem" return d # If just a base, return the IRI if irir.base and not irir.stem and not irir.exclusion: return self.shex_iri(irir.base) rval = dict(type="stemRange") rval.update(self.shex_iri_stem(irir)) if irir.exclusion: rval["exclusions"] = [add_stem_type(self.shex_iri_stem(e), e) for e in irir.exclusion] return rval def shex_rdf_literal(self, lit: RDFLiteral) -> str: rval = '"' + lit.value() + '"' if lit.datatype: rval += '^^' + self.shex_iri(lit.datatype) if lit.langtag: rval += '@' + lit.langtag return rval def shex_iri(self, iri: IRI) -> str: return self._uri(str(iri)) def shex_iri_ref(self, ref: IRIRef) -> str: return self.shex_iri(ref.ref) def shex_prefixed_name(self, pn: PrefixedName) -> str: return self._uri(str(pn)) @staticmethod def shex_cardinality(target: dict, card: PyxbWrapper): minv = card.node.min if card.node.min is not None else 1 maxv = card.node.max if card.node.max is not None else 1 if minv == maxv: if minv != 1: # TODO: Fix comparison tests so we can substitute length here # target["length"] = minv target["min"] = minv target["max"] = maxv else: target["min"] = minv target["max"] = '*' if maxv == "unbounded" else maxv def _uri(self, element): """ Map element into a complete URI :param element: URI or QNAME :return: URI """ return self._prefixmap.uri_for(PyxbWrapper.proc_unicode(element))
class ShExSchema: """ ShEx XML Schema to JSON wrapper """ def __init__(self, dom_schema): """ Constructor - convert the supplied schema to json :param dom_schema: DOM document to convert """ self.schema = CreateFromDOM(dom_schema) self.json = dict(type="schema") self._prefixmap = PrefixMap(self.schema, dom_schema) self._exclude_prefixes = self.schema.exclude_prefixes.split(' ') + [ 'xml', 'xmlns' ] self.shex_schema() def shex_schema(self): """ <code>xs:Element name="Schema" type="shex:Schema</code> """ self.json["prefixes"] = { prefix: url for prefix, url in self._prefixmap.namespaces().items() if prefix is not None and url and prefix not in self._exclude_prefixes } if self.schema.startActions: self.json["startActs"] = self.shex_semantic_actions( self.schema.startActions) if self.schema.shape: self.json["shapes"] = { self._uri(s.label): self.shex_shape(s) for s in self.schema.shape } if self.schema.valueClass: self.json["valueClasses"] = \ {self.shex_iri(vc.definition.valueClassLabel if vc.definition else vc.external.ref): self.shex_value_class_definition(vc) for vc in self.schema.valueClass} if self.schema.start: self.json["start"] = self._uri(self.schema.start) def shex_shape(self, shape: Shape) -> dict: """ <code>xs:complexType name="shape"</code> :param shape: XML Shape :return: S-JSON Shape Entry """ rval = dict(type="shape") w_shape = PyxbWrapper(shape) self.shex_annotations_and_actions(rval, w_shape) [self.shex_expression_choice(rval, e) for e in w_shape.elements] for e in w_shape.elements: if e.type == "import_": rval.setdefault("inherit", []).append(self.shex_shape_ref(e.value.node)) elif e.type == "extra": rval.setdefault(e.type, []).append(self._uri(e.value.node.ref)) # shape.label is the dictionary key in the Schema container if shape.virtual: rval["virtual"] = shape.virtual if shape.closed: rval["closed"] = shape.closed return rval @staticmethod def _typed_expression(typ: str, val: dict) -> dict: val["type"] = typ return val def shex_expression_choice(self, target: dict, e: PyxbWrapper.PyxbElement) -> dict: """ <code>xs:group name="ExpressionChoice"</code> :param target: target type with ExpressionChoice mixin :param e: Wrapper for ExpressionChoice element :return: target """ if e.type in ["someOf", "group"]: expr = self.shex_shape_constraint(e.value.node) elif e.type == "tripleConstraint": expr = self.shex_triple_constraint(e.value.node) elif e.type == "include": expr = dict(include=self._uri(e.value.node.ref)) else: expr = None if expr: target["expression"] = self._typed_expression(e.type, expr) return target def shex_annotations_and_actions(self, target: dict, ew: PyxbWrapper): """ <code>xs:group name="AnnotationsAndActions</code> :param target: dictionary using the group :param ew: xml element that contains the group """ for e in ew.elements: if e.type == "actions": target["semActs"] = self.shex_semantic_actions(e.value.node) elif e.type == "annotation": target.setdefault("annotations", []).append( self.shex_annotation(e.value.node)) def shex_shape_constraint(self, sc: ShapeConstraint) -> dict: """ <code>xs:complexType name="ShapeConstraint"</code> :param sc: A complete shape constraint :return: S-JSON expression """ rval = dict() sc_wrapper = PyxbWrapper(sc) for e in sc_wrapper.elements: entry = self.shex_expression_choice({}, e) if "expression" in entry: rval.setdefault("expressions", []).append(entry["expression"]) self.shex_annotations_and_actions(rval, sc_wrapper) self.shex_cardinality(rval, sc_wrapper) return rval def shex_triple_constraint(self, tc: TripleConstraint) -> dict: """ <code>xs:complexType name="TripleConstraint"</code> :param tc: TripleConstraint to process :return: SJson equivalent """ assert not ((tc.objectConstraint or tc.object or tc.objectShape or tc.objectType) and (tc.subjectConstraint or tc.subject or tc.subjectShape or tc.subjectType)), \ "Cannot mix subject and object constraints" tc_dict = dict(type="tripleConstraint", predicate=self.shex_iri(tc.predicate)) if tc.valueClass: tc_dict["valueClassRef"] = self.shex_value_class_label( tc.valueClass) else: vc_dict = dict(type="valueClass") if tc.objectConstraint: self.shex_triple_constraint_value_class( vc_dict, tc.objectConstraint) if tc.object: vc_dict["values"] = [self.shex_iri(tc.object)] if tc.objectShape: vc_dict["reference"] = self.shex_shape_label(tc.objectShape) if tc.objectType: vc_dict["nodeKind"] = self.shex_node_type(tc.objectType) if tc.subjectConstraint or tc.subject or tc.subjectShape or tc.subjectType or tc.inverse: tc_dict["inverse"] = True if tc.subjectConstraint: self.shex_triple_constraint_value_class( vc_dict, tc.subjectConstraint) if tc.subject: vc_dict["values"] = [self.shex_iri(tc.subject)] if tc.subjectShape: vc_dict["reference"] = self.shex_shape_label(tc.subjectShape) if tc.subjectType: vc_dict["nodeKind"] = self.shex_node_type(tc.subjectType) if tc.datatype: vc_dict["datatype"] = self._uri(tc.datatype) if tc.negated: tc_dict["negated"] = tc.negated tc_wrapper = PyxbWrapper(tc) self.shex_annotations_and_actions(tc_dict, tc_wrapper) self.shex_cardinality(tc_dict, tc_wrapper) tc_dict["value"] = vc_dict return tc_dict @staticmethod def shex_node_type(nt: NodeType): return str(nt).lower() def shex_annotation(self, annot: Annotation) -> list: """ <code>xs:complexType name="Annotation"</code> :param annot: Annotation :return: S-JSON equivalent """ rval = [self._uri(annot.iri)] if annot.iri else [] if annot.literal: rval.append(self.shex_rdf_literal(annot.literal)) else: rval.append(self.shex_iri_ref(annot.iriref)) return rval def shex_semantic_actions(self, acts: SemanticActions) -> list: """ <code>xs:complexType name="SemanticActions"</code> :param acts: actions :return: list of actions """ return [self.shex_semantic_action(a) for a in acts.action] def shex_semantic_action(self, act: SemanticAction) -> dict: """ <code>xs:complexType name="SemanticAction"</code> :param act: action :return: S-JSON representation """ # TODO: validating rval = {} if act.productionName: rval['name'] = self._uri(act.productionName.ref) if act.codeDecl: rval['contents'] = self.shex_code_decl(act.codeDecl) return rval @staticmethod def shex_code_decl(cd: CodeDecl): """ <code>xs:complexType name="CodeDecl" mixed="true"</code> :param cd: :return: """ return PyxbWrapper.mixed_content(cd) def shex_value_class_definition(self, vcd: ValueClassDefinition) -> dict: """ <code>xs:complexType name="ValueClassDefinition"</code> :param vcd: :return: """ rval = dict(type="valueClass") if vcd.external: rval["external"] = self.shex_value_class_ref(vcd.external) else: self.shex_inline_value_class_definition(rval, vcd.definition) if vcd.definition.actions: rval["semActs"] = self.shex_semantic_actions( vcd.definition.actions) return rval def shex_inline_value_class_definition( self, vc: dict, ivcd: InlineValueClassDefinition) -> list: """ <code>xs:complexType name="InlineValueClassDefinition"</code> :param vc: dictionary to record the actual elements :param ivcd: :return: """ # valueClassLabel becomes the identity vcd_wrapper = PyxbWrapper(ivcd) for e in vcd_wrapper.elements: if e.type == "nodetype": vc["nodeKind"] = self.shex_node_type(e.value.node) elif e.type == "datatype": vc[e.type] = self._uri(e.value.node) elif e.type == "facet": self.shex_xs_facet(vc, e.value.node) elif e.type == "or_": vc["reference"] = self.shex_group_shape_constr(e.value.node) elif e.type == "valueSet": vc["values"] = self.shex_value_set(e.value.node) else: assert False, "Unknown ValueClassExpression choice entry: %s" % e.type def shex_group_shape_constr(self, gsc: GroupShapeConstr) -> dict: """ <code>xs:complexType name="GroupShapeConstr"</code> :param gsc: :return: """ rval = dict(type="or", disjuncts=[self.shex_shape_ref(d) for d in gsc.disjunct]) if gsc.stringFacet: [self.shex_xs_facet(rval, e) for e in gsc.stringFacet] return rval # noinspection PyTypeChecker def shex_triple_constraint_value_class( self, vc: dict, tcvc: TripleConstraintValueClass) -> (dict, dict): return self.shex_inline_value_class_definition(vc, tcvc) def shex_value_class_label(self, l: ValueClassLabel) -> str: """ <code>xs:simpleType name="ValueClassLabel"</code> :param l: :return: """ return self.shex_iri(l) def shex_value_class_ref(self, lr: ValueClassRef) -> str: """ <code>xs:complexType name="ValueClassRef"</code> :param lr: :return: """ return self.shex_value_class_label(lr.ref) def shex_shape_label(self, sl: ShapeLabel) -> str: """ <code>xs:simpleType name="ShapeLabel"</code> :param sl: :return: """ return self.shex_iri(sl) def shex_shape_ref(self, sr: ShapeRef) -> str: """ <code>xs:complexType name="ShapeRef"</code> :param sr: :return: """ return self.shex_shape_label(sr.ref) @staticmethod def shex_code_label(cl: ProductionName) -> str: """ <code>xs:complexType name="CodeLabel"</code> :param cl: :return: """ return cl.ref.value() @staticmethod def _normalize_value(v): return int(v.integer) if v.integer is not None else \ float(v.double) if v.double is not None else float(v.decimal) @staticmethod def shex_xs_facet(target: dict, f: XSFacet): """ <code>xs:complexType name="XSFacet"</code> :param target: target dictionary (ValueClass) :param f: facet to transform """ if f.pattern: target["pattern"] = f.pattern elif f.not_: target["negated"] = True elif f.minLength: target["minlength"] = f.minLength elif f.maxLength: target["maxlength"] = f.maxLength elif f.length: target["length"] = f.length elif f.minValue: if f.minValue.open: target["minexclusive"] = ShExSchema._normalize_value( f.minValue) else: target["mininclusive"] = ShExSchema._normalize_value( f.minValue) elif f.maxValue: if f.maxValue.open: target["maxexclusive"] = ShExSchema._normalize_value( f.maxValue) else: target["maxinclusive"] = ShExSchema._normalize_value( f.maxValue) elif f.totalDigits: target["totaldigits"] = f.totalDigits elif f.fractionDigits: target["fractiondigits"] = f.fractionDigits else: assert False, "Unknown facet %s" % f # shex_endpoint is covered in the xs_facet logic above # noinspection PyTypeChecker @staticmethod def shex_string_facet(target: dict, sf: StringFacet): ShExSchema.shex_xs_facet(target, sf) # noinspection PyTypeChecker @staticmethod def shex_numeric_facet(target: dict, nf: NumericFacet): ShExSchema.shex_xs_facet(target, nf) def shex_value_set(self, vs: ValueSet) -> list: if vs.iriRange: return [self.shex_iri_range(e) for e in vs.iriRange] elif vs.rdfLiteral: return [self.shex_rdf_literal(e) for e in vs.rdfLiteral] elif vs.integer: return ['"%i"^^%s' % (e, XSD.integer) for e in vs.integer] elif vs.decimal: return ['"%d"^^%s' % (e, XSD.decimal) for e in vs.decimal] elif vs.double: return ['"%e"^^%s' % (e, XSD.double) for e in vs.double] elif vs.boolean: return ['"%s"^^%s' % (e, XSD.boolean) for e in vs.boolean] else: assert False, "Unknown ValueSet type" def shex_iri_stem(self, ist: IRIStem) -> dict: if ist.base and not ist.stem: return self.shex_iri(ist.base) else: return dict(stem=self.shex_iri(ist.base)) if ist.base else dict( stem=dict(type="wildcard")) def shex_iri_range(self, irir: IRIRange) -> object: """ :param irir: :return: """ def add_stem_type(d: dict, v: IRIStem): if v.stem: d["type"] = "stem" return d # If just a base, return the IRI if irir.base and not irir.stem and not irir.exclusion: return self.shex_iri(irir.base) rval = dict(type="stemRange") rval.update(self.shex_iri_stem(irir)) if irir.exclusion: rval["exclusions"] = [ add_stem_type(self.shex_iri_stem(e), e) for e in irir.exclusion ] return rval def shex_rdf_literal(self, lit: RDFLiteral) -> str: rval = '"' + lit.value() + '"' if lit.datatype: rval += '^^' + self.shex_iri(lit.datatype) if lit.langtag: rval += '@' + lit.langtag return rval def shex_iri(self, iri: IRI) -> str: return self._uri(str(iri)) def shex_iri_ref(self, ref: IRIRef) -> str: return self.shex_iri(ref.ref) def shex_prefixed_name(self, pn: PrefixedName) -> str: return self._uri(str(pn)) @staticmethod def shex_cardinality(target: dict, card: PyxbWrapper): minv = card.node.min if card.node.min is not None else 1 maxv = card.node.max if card.node.max is not None else 1 if minv == maxv: if minv != 1: # TODO: Fix comparison tests so we can substitute length here # target["length"] = minv target["min"] = minv target["max"] = maxv else: target["min"] = minv target["max"] = '*' if maxv == "unbounded" else maxv def _uri(self, element): """ Map element into a complete URI :param element: URI or QNAME :return: URI """ return self._prefixmap.uri_for(PyxbWrapper.proc_unicode(element))