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

Getting a bit further

parent 314bdf9b
Loading
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
import logging

from xmlschema.validators.simple_types import *
from xmlschema.validators.complex_types import *
from xmlschema.validators.groups import *
from xmlschema.validators.facets import *

from .TypeMapping import TypeMapping
from .ComplexTypeMapping import ComplexTypeMapping

log = logging.getLogger()

class ChoiceMapping(ComplexTypeMapping):
    @classmethod
    def process_choice(cls, choice: XsdGroup, current_ns : str):
        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 = TypeMapping.get_type_from_elem(c, current_ns)
            oneOf.append({
                "type" : "object",
                "properties" : {
                    c.local_name : t
                },
                "required" : [c.local_name]
            })
        return oneOf   

    def map(self, xst : BaseXsdType):
        log.debug(f"Attempting mapping of {xst} to choice")
        j = super().map(xst)
        if j is None:
            log.debug("Not a complex type, giving up")
            return None
        content = xst.content
        if (content.model != 'choice'):
            log.debug("Not a choice, giving up")
            return None
        return { 'oneOf' : ChoiceMapping.process_choice(content, xst.namespaces[''])}
+11 −0
Original line number Diff line number Diff line
from xmlschema.validators.complex_types import *

from .TypeMapping import TypeMapping

class ComplexTypeMapping(TypeMapping):
    def map(self, xst: BaseXsdType):
        if not (type(xst) is XsdComplexType):
            return None
        return {
            "type" : "object"
        }
+80 −0
Original line number Diff line number Diff line
import logging

from xmlschema.validators.simple_types import *
from xmlschema.validators.complex_types import *
from xmlschema.validators.groups import *
from xmlschema.validators.facets import *

from .TypeMapping import TypeMapping
from .ChoiceMapping import ChoiceMapping
from .ComplexTypeMapping import ComplexTypeMapping

log = logging.getLogger()


class SequenceMapping(ComplexTypeMapping):
    def map(self, xst: BaseXsdType):
        log.debug(f"Attempting mapping of {xst} to sequence")
        j = super().map(xst)
        if j is None:
            log.debug("Not a complex type, giving up")
            return None
        content = xst.content
        if (content.model != 'sequence'):
            log.debug("Not a sequence, giving up")
            return None
        mapped_type = {
            'type' : 'object',
            'properties' : {},
            'required' : []
        }

        # Not going to try and do all of this automatically for now
        # Only make insert the xsiType parameter
        if (xst.base_type):
            # mapped_type['__DESCENDENT_OF__'] = TypeMapping.get_ref_for(xst.base_type, xst.namespaces[''])
            mapped_type['properties']['@xsi:type'] = {
                "type" : "string",
                "enum" : xst.name
            }
            mapped_type['required'].append('@xsi:type')
        # if xst.abstract:
        #     mapped_type['__ABSTRACT__'] = True
        #     pass

        inner_choice = None
        for c in list(content.iter_model()):
            log.debug(f"Processing model item {c}")
            if type(c) is XsdElement:
                if c.effective_max_occurs != 1:
                    mapped_type['properties'][c.local_name] = {
                        "type" : "array",
                        "items" : TypeMapping.get_type_from_elem(c, xst.namespaces[''])
                    }
                    if c.effective_max_occurs:
                         mapped_type['properties'][c.local_name]['maxItems'] = c.effective_max_occurs
                    if c.effective_min_occurs > 0:
                         mapped_type['properties'][c.local_name]['minItems'] = c.effective_min_occurs
                else:
                    mapped_type['properties'][c.local_name] = TypeMapping.get_type_from_elem(c, xst.namespaces[''])
                    if c.effective_min_occurs == 1:
                        mapped_type['required'].append(c.local_name)
            elif type(c) is XsdGroup:
                if inner_choice:
                    raise Exception (f"Second group '{c.local_name}' encountered in {xst}")
                if c.model != "choice":
                    raise Exception (f"Don't know what to do with inner group {c} in {xst} - not a choice")
                inner_choice = ChoiceMapping.process_choice(c, xst.namespaces[''])
            elif type(c) is XsdAnyElement:
                mapped_type = {}
            else:
                raise Exception(f"Unknown element type {c}")
        if (inner_choice):
            return { 
                'allOf' : [
                    mapped_type,
                    {'oneOf' : inner_choice}
                ]
            }
        else:
            return mapped_type
+18 −0
Original line number Diff line number Diff line
import logging

from xmlschema.validators.complex_types import *
from xmlschema.validators.simple_types import XsdAtomicRestriction

from .TypeMapping import TypeMapping

log = logging.getLogger()

class SimpleTypeMapping(TypeMapping):
    def map(self, xst: BaseXsdType):
        log.debug(f"Attempting mapping of {xst} to simple type")
        if not (type(xst) is XsdAtomicRestriction):
            log.debug("Type is not an XsdAtomicRestriction, giving up")
            return None
        return {
            "$ref" : xst.base_type.name
        }
 No newline at end of file
+70 −0
Original line number Diff line number Diff line
import logging
from abc import ABC, abstractmethod

from xmlschema.validators.simple_types import *
from xmlschema.validators.complex_types import *
from xmlschema.validators.groups import *
from xmlschema.validators.facets import *

log = logging.getLogger()

class TypeMapping(ABC):
    ns_to_id_map = {}

    XSD_NS = "http://www.w3.org/2001/XMLSchema"

    XSD_TYPE_MAP = {
        "string" : { "type" : "string" },
        "normalizedString" : { "type" : "string", "pattern" : "^[^\r\n\t]*$"},
        "dateTime" : { "type" : "string"},
        "token" : { "type" : "string", "pattern" : "^[^\r\n\t]*$"},
        "anyURI" : { "type" : "string" },

        "integer" : { "type" : "integer"},
        "nonNegativeInteger" : { "type" : "integer", "minimum" : 0},
        "positiveInteger" : { "type" : "integer", "minimum" : 1},

        "boolean" : { "type" : "boolean" },

        "hexBinary" : { "type" : "string", "pattern" : "^([a-fA-F0-9]{2})*$"},
        "base64Binary" : { "type" : "string", "pattern" : "^[-A-Za-z0-9+/]*={0,3}$"},

        "anyType" : {}
    }    

    @abstractmethod
    def map(self, xst : BaseXsdType):
        return None

    @classmethod
    def extract_namespace(cls, qname: str):
        match = re.search(r'^\{([^\{\}]+)\}(([^\{\}]+))$', qname)
        if match is None:
            return None
        return match.group(1)

    @classmethod
    def get_ref_for(cls, xsd_type: XsdType, current_ns : str):
        ns = cls.extract_namespace(xsd_type.name)
        if ns == current_ns:
            return { "$ref" : f"#/$defs/{xsd_type.local_name}" }
        else:
            mapped_id = cls.ns_to_id_map[ns]
            return { "$ref" : f"{mapped_id}#/$defs/{xsd_type.local_name}"}        

    @classmethod
    def get_type_from_elem(cls, elem: XsdElement, current_ns : str):
        ns = cls.extract_namespace(elem.type.name)
        if (ns == TypeMapping.XSD_NS):
            # this should be an XSD primitive type
            return dict(TypeMapping.XSD_TYPE_MAP[elem.type.local_name])
        else:
            return cls.get_ref_for(elem.type, current_ns)







Loading