Loading common.json 0 → 100644 +7 −0 Original line number Diff line number Diff line { "$id" : "130120/common", "$defs" : { "ObjectIdentifier" : { "$ref" : "#/$defs/ObjectRoot"}, "ObjectRoot" : {"type" : "integer"} } } No newline at end of file core.json 0 → 100644 +558 −0 Original line number Diff line number Diff line { "$id": "core", "oneOf": [ { "$ref": "#/$defs/HI1Message" } ], "$defs": { "ObjectIdentifier": { "$ref": "etsi103280.json#/$defs/UUID" }, "HI1Message": { "type": "object", "properties": { "Header": { "$ref": "#/$defs/MessageHeader" }, "Payload": { "$ref": "#/$defs/MessagePayload" }, "Signature": { "$ref": "xmldsig.json#/$defs/SignatureType" } }, "required": [ "Header", "Payload" ] }, "MessageHeader": { "type": "object", "properties": { "SenderIdentifier": { "$ref": "#/$defs/EndpointID" }, "ReceiverIdentifier": { "$ref": "#/$defs/EndpointID" }, "TransactionIdentifier": { "$ref": "etsi103280.json#/$defs/UUID" }, "Timestamp": { "$ref": "etsi103280.json#/$defs/QualifiedMicrosecondDateTime" }, "Version": { "$ref": "#/$defs/Version" } }, "required": [ "SenderIdentifier", "ReceiverIdentifier", "TransactionIdentifier", "Timestamp", "Version" ] }, "Version": { "type": "object", "properties": { "ETSIVersion": { "$ref": "common.json#/$defs/ETSIVersion" }, "NationalProfileOwner": { "$ref": "etsi103280.json#/$defs/ShortString" }, "NationalProfileVersion": { "$ref": "etsi103280.json#/$defs/ShortString" } }, "required": [ "ETSIVersion", "NationalProfileOwner", "NationalProfileVersion" ] }, "EndpointID": { "type": "object", "properties": { "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "UniqueIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" } }, "required": [ "CountryCode", "UniqueIdentifier" ] }, "MessagePayload": { "oneOf": [ { "type": "object", "properties": { "RequestPayload": { "$ref": "#/$defs/RequestPayload" } }, "required": [ "RequestPayload" ] }, { "type": "object", "properties": { "ResponsePayload": { "$ref": "#/$defs/ResponsePayload" } }, "required": [ "ResponsePayload" ] } ] }, "RequestPayload": { "type": "object", "properties": { "ActionRequests": { "$ref": "#/$defs/ActionRequests" } }, "required": [ "ActionRequests" ] }, "ActionRequests": { "type": "object", "properties": { "ActionRequest": { "$ref": "#/$defs/ActionRequest" } }, "required": [ "ActionRequest" ] }, "ResponsePayload": { "oneOf": [ { "type": "object", "properties": { "ActionResponses": { "$ref": "#/$defs/ActionResponses" } }, "required": [ "ActionResponses" ] }, { "type": "object", "properties": { "ErrorInformation": { "$ref": "#/$defs/ActionUnsuccesfulInformation" } }, "required": [ "ErrorInformation" ] } ] }, "ActionResponses": { "type": "object", "properties": { "ActionResponse": { "$ref": "#/$defs/ActionResponse" } }, "required": [ "ActionResponse" ] }, "ActionRequest": { "allOf": [ { "type": "object", "properties": { "ActionIdentifier": { "type": "integer", "minimum": 0 } }, "required": [ "ActionIdentifier" ] }, { "oneOf": [ { "type": "object", "properties": { "GET": { "$ref": "#/$defs/GETRequest" } }, "required": [ "GET" ] }, { "type": "object", "properties": { "CREATE": { "$ref": "#/$defs/CREATERequest" } }, "required": [ "CREATE" ] }, { "type": "object", "properties": { "UPDATE": { "$ref": "#/$defs/UPDATERequest" } }, "required": [ "UPDATE" ] }, { "type": "object", "properties": { "LIST": { "$ref": "#/$defs/LISTRequest" } }, "required": [ "LIST" ] }, { "type": "object", "properties": { "DELIVER": { "$ref": "#/$defs/DELIVERRequest" } }, "required": [ "DELIVER" ] } ] } ] }, "ActionResponse": { "allOf": [ { "type": "object", "properties": { "ActionIdentifier": { "type": "integer", "minimum": 0 } }, "required": [ "ActionIdentifier" ] }, { "oneOf": [ { "type": "object", "properties": { "GETResponse": { "$ref": "#/$defs/GETResponse" } }, "required": [ "GETResponse" ] }, { "type": "object", "properties": { "CREATEResponse": { "$ref": "#/$defs/CREATEResponse" } }, "required": [ "CREATEResponse" ] }, { "type": "object", "properties": { "UPDATEResponse": { "$ref": "#/$defs/UPDATEResponse" } }, "required": [ "UPDATEResponse" ] }, { "type": "object", "properties": { "LISTResponse": { "$ref": "#/$defs/LISTResponse" } }, "required": [ "LISTResponse" ] }, { "type": "object", "properties": { "ErrorInformation": { "$ref": "#/$defs/ActionUnsuccesfulInformation" } }, "required": [ "ErrorInformation" ] }, { "type": "object", "properties": { "DELIVERResponse": { "$ref": "#/$defs/DELIVERResponse" } }, "required": [ "DELIVERResponse" ] } ] } ] }, "GETRequest": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [ "Identifier" ] }, "GETResponse": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "CREATERequest": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "CREATEResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier" ] }, "UPDATERequest": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "UPDATEResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier" ] }, "LISTRequest": { "type": "object", "properties": { "ObjectType": { "$ref": "common.json#/$defs/DictionaryEntry" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" } }, "required": [] }, "LISTResponse": { "type": "object", "properties": { "ListResponseRecord": { "$ref": "#/$defs/ListResponseRecord" } }, "required": [] }, "ListResponseRecord": { "type": "object", "properties": { "ObjectType": { "$ref": "common.json#/$defs/DictionaryEntry" }, "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "OwnerIdentifier": { "$ref": "etsi103280.json#/$defs/ShortString" }, "Generation": { "type": "integer", "minimum": 0 }, "ExternalIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" } }, "required": [ "ObjectType", "Identifier", "Generation" ] }, "ActionUnsuccesfulInformation": { "type": "object", "properties": { "ErrorCode": { "type": "integer", "minimum": 0 }, "ErrorDescription": { "$ref": "etsi103280.json#/$defs/LongString" } }, "required": [ "ErrorCode", "ErrorDescription" ] }, "DELIVERRequest": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier", "HI1Object" ] }, "DELIVERResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [ "Identifier" ] }, "HI1Object": { "type": "object", "properties": { "ObjectIdentifier": { "$ref": "#/$defs/ObjectIdentifier" }, "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "OwnerIdentifier": { "$ref": "etsi103280.json#/$defs/ShortString" }, "Generation": { "type": "integer", "minimum": 0 }, "ExternalIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" }, "AssociatedObjects": { "$ref": "#/$defs/AssociatedObjects" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" }, "NationalHandlingParameters": { "$ref": "#/$defs/NationalHandlingParameters" } }, "required": [ "ObjectIdentifier" ] }, "AssociatedObjects": { "type": "object", "properties": { "AssociatedObject": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [] }, "NationalHandlingParameters": { "type": "object", "properties": { "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" } }, "required": [ "CountryCode" ] } } } No newline at end of file etsi103280.json 0 → 100644 +11 −0 Original line number Diff line number Diff line { "$id" : "130120/common", "$defs" : { "ObjectIdentifier" : { "$ref" : "#/$defs/ObjectRoot"}, "ObjectRoot" : {"type" : "integer"}, "UUID" : { "type" : "string", "pattern" : "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$" } } } No newline at end of file test.py 0 → 100644 +189 −0 Original line number Diff line number Diff line import json import logging from pathlib import Path from pprint import pprint from xmlschema import * from xmlschema.validators.complex_types import XsdComplexType from xmlschema.validators.simple_types import XsdAtomicRestriction, XsdAtomicBuiltin from xmlschema.validators.groups import * schemas = [ "103120/schema/ts_103120_Authorisation.xsd", "103120/schema/ts_103120_Common.xsd", "103120/schema/ts_103120_Delivery.xsd", "103120/schema/ts_103120_Document.xsd", "103120/schema/ts_103120_Notification.xsd", "103120/schema/ts_103120_Task.xsd", "103280/TS_103_280.xsd", "testing/deps/xmldsig/xmldsig-core-schema.xsd"] schemaLocations = [] for schemaFile in schemas: try: xs = XMLSchema(schemaFile, validation='skip') schemaLocations.append((xs.target_namespace, str(Path(schemaFile).resolve()))) print (" [ {0} -> {1} ]".format(xs.target_namespace, schemaFile)) except XMLSchemaParseError as ex: print (" [ {0} failed to parse: {1} ]".format(schemaFile, ex)) coreSchema = XMLSchema('103120/schema/ts_103120_Core.xsd', locations = schemaLocations) js = { "$id" : "core", "oneOf" : [], "$defs" : {} } ns_mappings = { 'http://uri.etsi.org/03120/common/2019/10/Core' : 'core', 'http://uri.etsi.org/03120/common/2016/02/Common' : 'common', 'http://uri.etsi.org/03280/common/2017/07' : 'etsi103280', 'http://www.w3.org/2000/09/xmldsig#' : 'xmldsig' } primitive_type_mappings = { "token" : { "type" : "string"}, "string" : { "type" : "string"}, "nonNegativeInteger" : { "type" : "integer", "minimum" : 0}, "anyType" : {} } def process_qname(qname): namespace = qname[1:qname.find('}')] token = qname[qname.find('}')+1:] return token, namespace def get_type_from_elem(elem: XsdElement, local_id): t = elem.type ns = t.name[1:t.name.find('}')] if (ns == "http://www.w3.org/2001/XMLSchema"): # this should be an XSD primitive type mapped_type = primitive_type_mappings[t.local_name] return mapped_type else: # this needs to be a type in a namespace we know about mapped_ns = ns_mappings[ns] if (mapped_ns == local_id): return { "$ref" : f"#/$defs/{elem.type.local_name}"} else: return {"$ref" : f"{mapped_ns}.json#/$defs/{elem.type.local_name}"} def get_ref(token, ns, context): mapped_ns = ns_mappings[ns] if (mapped_ns == context): return f"#/$defs/{token}" else: return f"{mapped_ns}.json#/$defs/{token}" for elementName, element in coreSchema.elements.items(): print (f"Root element: {elementName} = {element}") token, ns = process_qname(element.type.name) js["oneOf"].append({ '$ref' : get_ref(token, ns, 'core') }) def process_choice(choice: XsdGroup): if choice.model != 'choice': raise Exception(f"Wrong group type: {c.model}") oneOf = [] for c in choice.iter_model(): if not (type(c) is XsdElement): raise Exception (f"Non-element {c} encountered in choice {choice}") t = get_type_from_elem(c, 'core') oneOf.append({ "type" : "object", "properties" : { c.local_name : t }, "required" : [c.local_name] }) return oneOf def process_atomic_restriction (sctype): r = {} print (f" Atomic restriction: {sctype}") token, ns = process_qname(sctype.name) print (f" [{ns}] {token}") print (f" Root type {sctype.root_type}") print (f" Base type {sctype.base_type}") print (" Facets....") for k, f in sctype.facets.items(): print (f" facet {k} = {f}") print (" Validators....") for v in list(sctype.validators): print (f" validator {v}") mappedType = primitive_type_mappings.get(sctype.base_type.name) if mappedType: r = mappedType print (f" Found primitive mapping to {mappedType}") if len(sctype.facets) > 0: raise Exception("Too many facets in primitive type") firstKey = sctype.facets.keys[0] if (firstKey != '{http://www.w3.org/2001/XMLSchema}pattern'): raise Exception (f"Unhandled facet {firstKey}") pattern = sctype.facets[firstKey] r['pattern'] = pattern.pattern if len(sctype.validators) > 0: raise Exception("Too many validators in primitive type") return token, r else: base_token, base_ns = process_qname(sctype.base_type.name) return token, { '$ref' : get_ref(base_token, base_ns, 'core')} for typeName, sctype in coreSchema.types.items(): print (f"Type: {typeName} = {type} ({type(sctype)}") if type(sctype) is XsdAtomicRestriction: token, typeDef = process_atomic_restriction(sctype) js["$defs"][token] = typeDef #print (dir(sctype)) if type(sctype) is XsdComplexType: content = sctype.content print(f" Content {content}") d = {} if type(content) is XsdGroup: if content.model == "sequence": print (" SEQUENCE!") d = { 'type' : 'object', 'properties' : {}, 'required' : [] } innerChoice = None for c in list(content.iter_model()): print (f" > {c}") if type(c) is XsdElement: d['properties'][c.local_name] = get_type_from_elem(c, 'core') if c.effective_min_occurs == 1: d['required'].append(c.local_name) elif type(c) is XsdGroup: if innerChoice: raise Exception ("Second group encountered") if c.model != "choice": raise Exception (f"Don't know what to do with inner {c}") innerChoice = process_choice(c) else: raise Exception(f"Unknown element type {c}") if (innerChoice): js["$defs"][sctype.local_name] = { 'allOf' : [ d, {'oneOf' : innerChoice} ] } else: js["$defs"][sctype.local_name] = d elif content.model =="choice": print (" CHOICE!") oneOf = process_choice(content) js["$defs"][sctype.local_name] = {'oneOf' : oneOf} else: raise Exception(f"Unknown content type {content}") pprint(js) Path('./core.json').write_text(json.dumps(js, indent=2)) No newline at end of file test_doc.json 0 → 100644 +8 −0 Original line number Diff line number Diff line { "HI1Message" : { "Header" : 45, "Payload" : { "RequestPayload" : "oops" } } } No newline at end of file Loading
common.json 0 → 100644 +7 −0 Original line number Diff line number Diff line { "$id" : "130120/common", "$defs" : { "ObjectIdentifier" : { "$ref" : "#/$defs/ObjectRoot"}, "ObjectRoot" : {"type" : "integer"} } } No newline at end of file
core.json 0 → 100644 +558 −0 Original line number Diff line number Diff line { "$id": "core", "oneOf": [ { "$ref": "#/$defs/HI1Message" } ], "$defs": { "ObjectIdentifier": { "$ref": "etsi103280.json#/$defs/UUID" }, "HI1Message": { "type": "object", "properties": { "Header": { "$ref": "#/$defs/MessageHeader" }, "Payload": { "$ref": "#/$defs/MessagePayload" }, "Signature": { "$ref": "xmldsig.json#/$defs/SignatureType" } }, "required": [ "Header", "Payload" ] }, "MessageHeader": { "type": "object", "properties": { "SenderIdentifier": { "$ref": "#/$defs/EndpointID" }, "ReceiverIdentifier": { "$ref": "#/$defs/EndpointID" }, "TransactionIdentifier": { "$ref": "etsi103280.json#/$defs/UUID" }, "Timestamp": { "$ref": "etsi103280.json#/$defs/QualifiedMicrosecondDateTime" }, "Version": { "$ref": "#/$defs/Version" } }, "required": [ "SenderIdentifier", "ReceiverIdentifier", "TransactionIdentifier", "Timestamp", "Version" ] }, "Version": { "type": "object", "properties": { "ETSIVersion": { "$ref": "common.json#/$defs/ETSIVersion" }, "NationalProfileOwner": { "$ref": "etsi103280.json#/$defs/ShortString" }, "NationalProfileVersion": { "$ref": "etsi103280.json#/$defs/ShortString" } }, "required": [ "ETSIVersion", "NationalProfileOwner", "NationalProfileVersion" ] }, "EndpointID": { "type": "object", "properties": { "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "UniqueIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" } }, "required": [ "CountryCode", "UniqueIdentifier" ] }, "MessagePayload": { "oneOf": [ { "type": "object", "properties": { "RequestPayload": { "$ref": "#/$defs/RequestPayload" } }, "required": [ "RequestPayload" ] }, { "type": "object", "properties": { "ResponsePayload": { "$ref": "#/$defs/ResponsePayload" } }, "required": [ "ResponsePayload" ] } ] }, "RequestPayload": { "type": "object", "properties": { "ActionRequests": { "$ref": "#/$defs/ActionRequests" } }, "required": [ "ActionRequests" ] }, "ActionRequests": { "type": "object", "properties": { "ActionRequest": { "$ref": "#/$defs/ActionRequest" } }, "required": [ "ActionRequest" ] }, "ResponsePayload": { "oneOf": [ { "type": "object", "properties": { "ActionResponses": { "$ref": "#/$defs/ActionResponses" } }, "required": [ "ActionResponses" ] }, { "type": "object", "properties": { "ErrorInformation": { "$ref": "#/$defs/ActionUnsuccesfulInformation" } }, "required": [ "ErrorInformation" ] } ] }, "ActionResponses": { "type": "object", "properties": { "ActionResponse": { "$ref": "#/$defs/ActionResponse" } }, "required": [ "ActionResponse" ] }, "ActionRequest": { "allOf": [ { "type": "object", "properties": { "ActionIdentifier": { "type": "integer", "minimum": 0 } }, "required": [ "ActionIdentifier" ] }, { "oneOf": [ { "type": "object", "properties": { "GET": { "$ref": "#/$defs/GETRequest" } }, "required": [ "GET" ] }, { "type": "object", "properties": { "CREATE": { "$ref": "#/$defs/CREATERequest" } }, "required": [ "CREATE" ] }, { "type": "object", "properties": { "UPDATE": { "$ref": "#/$defs/UPDATERequest" } }, "required": [ "UPDATE" ] }, { "type": "object", "properties": { "LIST": { "$ref": "#/$defs/LISTRequest" } }, "required": [ "LIST" ] }, { "type": "object", "properties": { "DELIVER": { "$ref": "#/$defs/DELIVERRequest" } }, "required": [ "DELIVER" ] } ] } ] }, "ActionResponse": { "allOf": [ { "type": "object", "properties": { "ActionIdentifier": { "type": "integer", "minimum": 0 } }, "required": [ "ActionIdentifier" ] }, { "oneOf": [ { "type": "object", "properties": { "GETResponse": { "$ref": "#/$defs/GETResponse" } }, "required": [ "GETResponse" ] }, { "type": "object", "properties": { "CREATEResponse": { "$ref": "#/$defs/CREATEResponse" } }, "required": [ "CREATEResponse" ] }, { "type": "object", "properties": { "UPDATEResponse": { "$ref": "#/$defs/UPDATEResponse" } }, "required": [ "UPDATEResponse" ] }, { "type": "object", "properties": { "LISTResponse": { "$ref": "#/$defs/LISTResponse" } }, "required": [ "LISTResponse" ] }, { "type": "object", "properties": { "ErrorInformation": { "$ref": "#/$defs/ActionUnsuccesfulInformation" } }, "required": [ "ErrorInformation" ] }, { "type": "object", "properties": { "DELIVERResponse": { "$ref": "#/$defs/DELIVERResponse" } }, "required": [ "DELIVERResponse" ] } ] } ] }, "GETRequest": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [ "Identifier" ] }, "GETResponse": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "CREATERequest": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "CREATEResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier" ] }, "UPDATERequest": { "type": "object", "properties": { "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "HI1Object" ] }, "UPDATEResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier" ] }, "LISTRequest": { "type": "object", "properties": { "ObjectType": { "$ref": "common.json#/$defs/DictionaryEntry" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" } }, "required": [] }, "LISTResponse": { "type": "object", "properties": { "ListResponseRecord": { "$ref": "#/$defs/ListResponseRecord" } }, "required": [] }, "ListResponseRecord": { "type": "object", "properties": { "ObjectType": { "$ref": "common.json#/$defs/DictionaryEntry" }, "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "OwnerIdentifier": { "$ref": "etsi103280.json#/$defs/ShortString" }, "Generation": { "type": "integer", "minimum": 0 }, "ExternalIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" } }, "required": [ "ObjectType", "Identifier", "Generation" ] }, "ActionUnsuccesfulInformation": { "type": "object", "properties": { "ErrorCode": { "type": "integer", "minimum": 0 }, "ErrorDescription": { "$ref": "etsi103280.json#/$defs/LongString" } }, "required": [ "ErrorCode", "ErrorDescription" ] }, "DELIVERRequest": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" }, "HI1Object": { "$ref": "#/$defs/HI1Object" } }, "required": [ "Identifier", "HI1Object" ] }, "DELIVERResponse": { "type": "object", "properties": { "Identifier": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [ "Identifier" ] }, "HI1Object": { "type": "object", "properties": { "ObjectIdentifier": { "$ref": "#/$defs/ObjectIdentifier" }, "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" }, "OwnerIdentifier": { "$ref": "etsi103280.json#/$defs/ShortString" }, "Generation": { "type": "integer", "minimum": 0 }, "ExternalIdentifier": { "$ref": "etsi103280.json#/$defs/LongString" }, "AssociatedObjects": { "$ref": "#/$defs/AssociatedObjects" }, "LastChanged": { "$ref": "etsi103280.json#/$defs/QualifiedDateTime" }, "NationalHandlingParameters": { "$ref": "#/$defs/NationalHandlingParameters" } }, "required": [ "ObjectIdentifier" ] }, "AssociatedObjects": { "type": "object", "properties": { "AssociatedObject": { "$ref": "#/$defs/ObjectIdentifier" } }, "required": [] }, "NationalHandlingParameters": { "type": "object", "properties": { "CountryCode": { "$ref": "etsi103280.json#/$defs/ISOCountryCode" } }, "required": [ "CountryCode" ] } } } No newline at end of file
etsi103280.json 0 → 100644 +11 −0 Original line number Diff line number Diff line { "$id" : "130120/common", "$defs" : { "ObjectIdentifier" : { "$ref" : "#/$defs/ObjectRoot"}, "ObjectRoot" : {"type" : "integer"}, "UUID" : { "type" : "string", "pattern" : "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$" } } } No newline at end of file
test.py 0 → 100644 +189 −0 Original line number Diff line number Diff line import json import logging from pathlib import Path from pprint import pprint from xmlschema import * from xmlschema.validators.complex_types import XsdComplexType from xmlschema.validators.simple_types import XsdAtomicRestriction, XsdAtomicBuiltin from xmlschema.validators.groups import * schemas = [ "103120/schema/ts_103120_Authorisation.xsd", "103120/schema/ts_103120_Common.xsd", "103120/schema/ts_103120_Delivery.xsd", "103120/schema/ts_103120_Document.xsd", "103120/schema/ts_103120_Notification.xsd", "103120/schema/ts_103120_Task.xsd", "103280/TS_103_280.xsd", "testing/deps/xmldsig/xmldsig-core-schema.xsd"] schemaLocations = [] for schemaFile in schemas: try: xs = XMLSchema(schemaFile, validation='skip') schemaLocations.append((xs.target_namespace, str(Path(schemaFile).resolve()))) print (" [ {0} -> {1} ]".format(xs.target_namespace, schemaFile)) except XMLSchemaParseError as ex: print (" [ {0} failed to parse: {1} ]".format(schemaFile, ex)) coreSchema = XMLSchema('103120/schema/ts_103120_Core.xsd', locations = schemaLocations) js = { "$id" : "core", "oneOf" : [], "$defs" : {} } ns_mappings = { 'http://uri.etsi.org/03120/common/2019/10/Core' : 'core', 'http://uri.etsi.org/03120/common/2016/02/Common' : 'common', 'http://uri.etsi.org/03280/common/2017/07' : 'etsi103280', 'http://www.w3.org/2000/09/xmldsig#' : 'xmldsig' } primitive_type_mappings = { "token" : { "type" : "string"}, "string" : { "type" : "string"}, "nonNegativeInteger" : { "type" : "integer", "minimum" : 0}, "anyType" : {} } def process_qname(qname): namespace = qname[1:qname.find('}')] token = qname[qname.find('}')+1:] return token, namespace def get_type_from_elem(elem: XsdElement, local_id): t = elem.type ns = t.name[1:t.name.find('}')] if (ns == "http://www.w3.org/2001/XMLSchema"): # this should be an XSD primitive type mapped_type = primitive_type_mappings[t.local_name] return mapped_type else: # this needs to be a type in a namespace we know about mapped_ns = ns_mappings[ns] if (mapped_ns == local_id): return { "$ref" : f"#/$defs/{elem.type.local_name}"} else: return {"$ref" : f"{mapped_ns}.json#/$defs/{elem.type.local_name}"} def get_ref(token, ns, context): mapped_ns = ns_mappings[ns] if (mapped_ns == context): return f"#/$defs/{token}" else: return f"{mapped_ns}.json#/$defs/{token}" for elementName, element in coreSchema.elements.items(): print (f"Root element: {elementName} = {element}") token, ns = process_qname(element.type.name) js["oneOf"].append({ '$ref' : get_ref(token, ns, 'core') }) def process_choice(choice: XsdGroup): if choice.model != 'choice': raise Exception(f"Wrong group type: {c.model}") oneOf = [] for c in choice.iter_model(): if not (type(c) is XsdElement): raise Exception (f"Non-element {c} encountered in choice {choice}") t = get_type_from_elem(c, 'core') oneOf.append({ "type" : "object", "properties" : { c.local_name : t }, "required" : [c.local_name] }) return oneOf def process_atomic_restriction (sctype): r = {} print (f" Atomic restriction: {sctype}") token, ns = process_qname(sctype.name) print (f" [{ns}] {token}") print (f" Root type {sctype.root_type}") print (f" Base type {sctype.base_type}") print (" Facets....") for k, f in sctype.facets.items(): print (f" facet {k} = {f}") print (" Validators....") for v in list(sctype.validators): print (f" validator {v}") mappedType = primitive_type_mappings.get(sctype.base_type.name) if mappedType: r = mappedType print (f" Found primitive mapping to {mappedType}") if len(sctype.facets) > 0: raise Exception("Too many facets in primitive type") firstKey = sctype.facets.keys[0] if (firstKey != '{http://www.w3.org/2001/XMLSchema}pattern'): raise Exception (f"Unhandled facet {firstKey}") pattern = sctype.facets[firstKey] r['pattern'] = pattern.pattern if len(sctype.validators) > 0: raise Exception("Too many validators in primitive type") return token, r else: base_token, base_ns = process_qname(sctype.base_type.name) return token, { '$ref' : get_ref(base_token, base_ns, 'core')} for typeName, sctype in coreSchema.types.items(): print (f"Type: {typeName} = {type} ({type(sctype)}") if type(sctype) is XsdAtomicRestriction: token, typeDef = process_atomic_restriction(sctype) js["$defs"][token] = typeDef #print (dir(sctype)) if type(sctype) is XsdComplexType: content = sctype.content print(f" Content {content}") d = {} if type(content) is XsdGroup: if content.model == "sequence": print (" SEQUENCE!") d = { 'type' : 'object', 'properties' : {}, 'required' : [] } innerChoice = None for c in list(content.iter_model()): print (f" > {c}") if type(c) is XsdElement: d['properties'][c.local_name] = get_type_from_elem(c, 'core') if c.effective_min_occurs == 1: d['required'].append(c.local_name) elif type(c) is XsdGroup: if innerChoice: raise Exception ("Second group encountered") if c.model != "choice": raise Exception (f"Don't know what to do with inner {c}") innerChoice = process_choice(c) else: raise Exception(f"Unknown element type {c}") if (innerChoice): js["$defs"][sctype.local_name] = { 'allOf' : [ d, {'oneOf' : innerChoice} ] } else: js["$defs"][sctype.local_name] = d elif content.model =="choice": print (" CHOICE!") oneOf = process_choice(content) js["$defs"][sctype.local_name] = {'oneOf' : oneOf} else: raise Exception(f"Unknown content type {content}") pprint(js) Path('./core.json').write_text(json.dumps(js, indent=2)) No newline at end of file
test_doc.json 0 → 100644 +8 −0 Original line number Diff line number Diff line { "HI1Message" : { "Header" : 45, "Payload" : { "RequestPayload" : "oops" } } } No newline at end of file