Commit ec338d9e authored by Mark Canterbury's avatar Mark Canterbury
Browse files

First attempt at translation

parent 3657cb3f
Loading
Loading
Loading
Loading
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