예제 #1
0
    def test_get_qname_functions(self):
        self.assertEqual(get_qname(XSD_NAMESPACE, 'element'), XSD_ELEMENT)
        self.assertEqual(get_qname(XSI_NAMESPACE, 'type'), XSI_TYPE)

        self.assertEqual(get_qname(XSI_NAMESPACE, ''), '')
        self.assertEqual(get_qname(XSI_NAMESPACE, None), None)
        self.assertEqual(get_qname(XSI_NAMESPACE, 0), 0)
        self.assertEqual(get_qname(XSI_NAMESPACE, False), False)
        self.assertRaises(TypeError, get_qname, XSI_NAMESPACE, True)
        self.assertEqual(get_qname(None, True), True)

        self.assertEqual(get_qname(None, 'element'), 'element')
        self.assertEqual(get_qname(None, ''), '')
        self.assertEqual(get_qname('', 'element'), 'element')
예제 #2
0
    def _parse_substitution_group(self):
        substitution_group = self.elem.get('substitutionGroup')
        if substitution_group is None:
            return

        try:
            substitution_group_qname = self.schema.resolve_qname(substitution_group)
        except ValueError as err:
            self.parse_error(err)
            return
        else:
            if substitution_group_qname[0] != '{':
                substitution_group_qname = get_qname(self.target_namespace, substitution_group_qname)

        try:
            head_element = self.maps.lookup_element(substitution_group_qname)
        except KeyError:
            self.parse_error("unknown substitutionGroup %r" % substitution_group)
            return
        else:
            if isinstance(head_element, tuple):
                self.parse_error("circularity found for substitutionGroup %r" % substitution_group)
                return
            elif 'substitution' in head_element.block:
                return

        final = head_element.final
        if self.type == head_element.type or self.type.name == XSD_ANY_TYPE:
            pass
        elif not self.type.is_derived(head_element.type):
            msg = "%r type is not of the same or a derivation of the head element %r type."
            self.parse_error(msg % (self, head_element))
        elif final == '#all' or 'extension' in final and 'restriction' in final:
            msg = "head element %r can't be substituted by an element that has a derivation of its type"
            self.parse_error(msg % head_element)
        elif 'extension' in final and self.type.is_derived(head_element.type, 'extension'):
            msg = "head element %r can't be substituted by an element that has an extension of its type"
            self.parse_error(msg % head_element)
        elif 'restriction' in final and self.type.is_derived(head_element.type, 'restriction'):
            msg = "head element %r can't be substituted by an element that has a restriction of its type"
            self.parse_error(msg % head_element)

        if self.type.name == XSD_ANY_TYPE and 'type' not in self.elem.attrib:
            self.type = self.maps.elements[substitution_group_qname].type

        try:
            self.maps.substitution_groups[substitution_group_qname].add(self)
        except KeyError:
            self.maps.substitution_groups[substitution_group_qname] = {self}
        finally:
            self._substitution_group = substitution_group_qname
예제 #3
0
    def _parse(self):
        super(XsdNotation, self)._parse()
        if not self.is_global:
            self.parse_error("a notation declaration must be global.",
                             self.elem)
        try:
            self.name = get_qname(self.target_namespace,
                                  self.elem.attrib['name'])
        except KeyError:
            self.parse_error("a notation must have a 'name'.", self.elem)

        if 'public' not in self.elem.attrib and 'system' not in self.elem.attrib:
            self.parse_error(
                "a notation must has a 'public' or a 'system' attribute.",
                self.elem)
예제 #4
0
    def _parse(self):
        super(XsdIdentity, self)._parse()
        elem = self.elem
        try:
            self.name = get_qname(self.target_namespace, elem.attrib['name'])
        except KeyError:
            self.parse_error("missing required attribute 'name'", elem)
            self.name = None

        child = self._parse_component(elem, required=False, strict=False)
        if child is None or child.tag != XSD_SELECTOR:
            self.parse_error("missing 'selector' declaration.", elem)
            self.selector = None
        else:
            self.selector = XsdSelector(child, self.schema, self)

        self.fields = []
        for child in self._iterparse_components(
                elem, start=int(self.selector is not None)):
            if child.tag == XSD_FIELD:
                self.fields.append(XsdFieldSelector(child, self.schema, self))
            else:
                self.parse_error("element %r not allowed here:" % child.tag,
                                 elem)
예제 #5
0
    def _parse(self):
        super(XsdComplexType, self)._parse()
        elem = self.elem
        if elem.tag == XSD_RESTRICTION:
            return  # a local restriction is already parsed by the caller

        if 'abstract' in elem.attrib:
            try:
                self.abstract = get_xml_bool_attribute(elem, 'abstract')
            except ValueError as err:
                self.parse_error(err, elem)

        if 'block' in elem.attrib:
            try:
                self._block = get_xsd_derivation_attribute(
                    elem, 'block', ('extension', 'restriction'))
            except ValueError as err:
                self.parse_error(err, elem)

        if 'final' in elem.attrib:
            try:
                self._final = get_xsd_derivation_attribute(
                    elem, 'final', ('extension', 'restriction'))
            except ValueError as err:
                self.parse_error(err, elem)

        if 'mixed' in elem.attrib:
            try:
                self.mixed = get_xml_bool_attribute(elem, 'mixed')
            except ValueError as err:
                self.parse_error(err, elem)

        try:
            self.name = get_qname(self.target_namespace, elem.attrib['name'])
        except KeyError:
            self.name = None
        else:
            if self.parent is not None:
                self.parse_error(
                    "attribute 'name' not allowed for a local complexType",
                    elem)

        content_elem = self._parse_component(elem,
                                             required=False,
                                             strict=False)
        if content_elem is None or content_elem.tag in \
                {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE}:
            #
            # complexType with empty content
            self.content_type = self.schema.BUILDERS.group_class(
                SEQUENCE_ELEMENT, self.schema, self)
            self._parse_content_tail(elem)

        elif content_elem.tag in {
                XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE
        }:
            #
            # complexType with child elements
            self.content_type = self.schema.BUILDERS.group_class(
                content_elem, self.schema, self)
            self._parse_content_tail(elem)

        elif content_elem.tag == XSD_SIMPLE_CONTENT:
            if 'mixed' in content_elem.attrib:
                self.parse_error(
                    "'mixed' attribute not allowed with simpleContent",
                    content_elem)

            derivation_elem = self._parse_derivation_elem(content_elem)
            if derivation_elem is None:
                return

            self.base_type = self._parse_base_type(derivation_elem)
            if derivation_elem.tag == XSD_RESTRICTION:
                self._parse_simple_content_restriction(derivation_elem,
                                                       self.base_type)
            else:
                self._parse_simple_content_extension(derivation_elem,
                                                     self.base_type)

            if content_elem is not elem[-1]:
                k = 2 if content_elem is not elem[0] else 1
                self.parse_error(
                    "unexpected tag %r after simpleContent declaration:" %
                    elem[k].tag, elem)

        elif content_elem.tag == XSD_COMPLEX_CONTENT:
            #
            # complexType with complexContent restriction/extension
            if 'mixed' in content_elem.attrib:
                self.mixed = content_elem.attrib['mixed'] in ('true', '1')

            derivation_elem = self._parse_derivation_elem(content_elem)
            if derivation_elem is None:
                return

            base_type = self._parse_base_type(derivation_elem,
                                              complex_content=True)
            if derivation_elem.tag == XSD_RESTRICTION:
                self._parse_complex_content_restriction(
                    derivation_elem, base_type)
            else:
                self._parse_complex_content_extension(derivation_elem,
                                                      base_type)

            if content_elem is not elem[-1]:
                k = 2 if content_elem is not elem[0] else 1
                self.parse_error(
                    "unexpected tag %r after complexContent declaration:" %
                    elem[k].tag, elem)
            if self.redefine or base_type is not self:
                self.base_type = base_type

        elif content_elem.tag == XSD_OPEN_CONTENT and self.schema.XSD_VERSION != '1.0':
            self.open_content = None

            if content_elem is elem[-1]:
                self.content_type = self.schema.BUILDERS.group_class(
                    SEQUENCE_ELEMENT, self.schema, self)
            else:
                for child, index in enumerate(elem):
                    if content_elem is not child:
                        continue
                    elif elem[index + 1].tag in {
                            XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE
                    }:
                        self.content_type = self.schema.BUILDERS.group_class(
                            elem[index + 1], self.schema, self)
                    else:
                        self.content_type = self.schema.BUILDERS.group_class(
                            SEQUENCE_ELEMENT, self.schema, self)
                    break
            self._parse_content_tail(elem)

        else:
            if self.schema.validation == 'skip':
                # Also generated by meta-schema validation for 'lax' and 'strict' modes
                self.parse_error(
                    "unexpected tag %r for complexType content:" %
                    content_elem.tag, elem)
            self.content_type = self.schema.create_any_content_group(self)
            self.attributes = self.schema.create_any_attribute_group(self)

        if self.redefine is None:
            if self.base_type is not None and self.base_type.name == self.name:
                self.parse_error("wrong definition with self-reference", elem)
        elif self.base_type is None or self.base_type.name != self.name:
            self.parse_error("wrong redefinition without self-reference", elem)
예제 #6
0
 def get_attribute(self, name):
     if name[0] != '{':
         return self.type.attributes[get_qname(self.type.target_namespace, name)]
     return self.type.attributes[name]
예제 #7
0
    def _parse_attributes(self):
        elem = self.elem
        attrib = elem.attrib
        self._parse_particle(elem)

        try:
            self.qualified = (self.form or self.schema.element_form_default) == 'qualified'
        except ValueError as err:
            self.parse_error(err)

        name = elem.get('name')
        if name is not None:
            if self.parent is None or self.qualified:
                self.name = get_qname(self.target_namespace, attrib['name'])
            else:
                self.name = attrib['name']
        elif self.parent is None:
            self.parse_error("missing 'name' in a global element declaration")
            self.name = elem.get('ref', 'nameless_%s' % str(id(self)))
        elif 'ref' not in attrib:
            self.parse_error("missing both 'name' and 'ref' attributes")
            self.name = elem.get('nameless_%s' % str(id(self)))
        else:
            try:
                element_name = self.schema.resolve_qname(attrib['ref'])
            except ValueError as err:
                self.parse_error(err)
                self.type = self.maps.types[XSD_ANY_TYPE]
                self.name = elem.get('nameless_%s' % str(id(self)))
            else:
                if not element_name:
                    self.parse_error("empty 'ref' attribute")
                    self.type = self.maps.types[XSD_ANY_TYPE]
                    self.name = elem.get('nameless_%s' % str(id(self)))
                else:
                    try:
                        xsd_element = self.maps.lookup_element(element_name)
                    except KeyError:
                        self.parse_error('unknown element %r' % element_name)
                        self.name = element_name
                        self.type = self.maps.types[XSD_ANY_TYPE]
                    else:
                        self._ref = xsd_element
                        self.name = xsd_element.name
                        self.type = xsd_element.type
                        self.qualified = xsd_element.qualified

            for attr_name in ('name', 'type', 'nillable', 'default', 'fixed', 'form',
                              'block', 'abstract', 'final', 'substitutionGroup'):
                if attr_name in attrib:
                    self.parse_error("attribute %r is not allowed when element reference is used." % attr_name)
            return

        if 'default' in attrib and 'fixed' in attrib:
            self.parse_error("'default' and 'fixed' attributes are mutually exclusive.")

        if 'abstract' in elem.attrib:
            try:
                self._abstract = get_xml_bool_attribute(elem, 'abstract')
            except ValueError as err:
                self.parse_error(err, elem)
            else:
                if self.parent is not None:
                    self.parse_error("local scope elements cannot have abstract attribute")

        if 'block' in elem.attrib:
            try:
                self._block = get_xsd_derivation_attribute(
                    elem, 'block', ('extension', 'restriction', 'substitution')
                )
            except ValueError as err:
                self.parse_error(err, elem)

        if self.parent is None:
            self._parse_properties('nillable')

            if 'final' in elem.attrib:
                try:
                    self._final = get_xsd_derivation_attribute(elem, 'final', ('extension', 'restriction'))
                except ValueError as err:
                    self.parse_error(err, elem)

            for attr_name in ('ref', 'form', 'minOccurs', 'maxOccurs'):
                if attr_name in attrib:
                    self.parse_error("attribute %r not allowed in a global element declaration" % attr_name)
        else:
            self._parse_properties('form', 'nillable')

            for attr_name in ('final', 'substitutionGroup'):
                if attr_name in attrib:
                    self.parse_error("attribute %r not allowed in a local element declaration" % attr_name)
예제 #8
0
    def load_xsd_globals(xsd_globals, schemas):
        redefinitions = []
        for schema in schemas:
            target_namespace = schema.target_namespace
            for elem in iterchildren_xsd_redefine(schema.root):
                location = elem.get('schemaLocation')
                if location is None:
                    continue
                for child in filter_function(elem):
                    qname = get_qname(target_namespace, child.attrib['name'])
                    redefinitions.append(
                        (qname, child, schema, schema.includes[location]))

            for elem in filter_function(schema.root):
                qname = get_qname(target_namespace, elem.attrib['name'])
                try:
                    xsd_globals[qname].append((elem, schema))
                except KeyError:
                    xsd_globals[qname] = (elem, schema)
                except AttributeError:
                    xsd_globals[qname] = [xsd_globals[qname], (elem, schema)]

        tags = Counter([x[0] for x in redefinitions])
        for qname, elem, schema, redefined_schema in redefinitions:

            # Checks multiple redefinitions
            if tags[qname] > 1:
                tags[qname] = 1

                redefined_schemas = [
                    x[3] for x in redefinitions if x[0] == qname
                ]
                if any(
                        redefined_schemas.count(x) > 1
                        for x in redefined_schemas):
                    schema.parse_error(
                        "multiple redefinition for {} {!r}".format(
                            local_name(elem.tag), qname), elem)
                else:
                    redefined_schemas = {
                        x[3]: x[2]
                        for x in redefinitions if x[0] == qname
                    }
                    for rs, s in redefined_schemas.items():
                        while True:
                            try:
                                s = redefined_schemas[s]
                            except KeyError:
                                break

                            if s is rs:
                                schema.parse_error(
                                    "circular redefinition for {} {!r}".format(
                                        local_name(elem.tag), qname), elem)
                                break

            # Append redefinition
            try:
                xsd_globals[qname].append((elem, schema))
            except KeyError:
                schema.parse_error("not a redefinition!", elem)
                # xsd_globals[qname] = elem, schema
            except AttributeError:
                xsd_globals[qname] = [xsd_globals[qname], (elem, schema)]
예제 #9
0
 def qualified_name(self):
     return get_qname(self.target_namespace, self.name)
예제 #10
0
    def iter_encode(self,
                    element_data,
                    validation='lax',
                    converter=None,
                    **kwargs):
        """
        Creates an iterator for encoding data to a list containing Element data.

        :param element_data: an ElementData instance with unencoded data.
        :param validation: the validation mode: can be 'lax', 'strict' or 'skip'.
        :param converter: an :class:`XMLSchemaConverter` subclass or instance.
        :param kwargs: Keyword arguments for the encoding process.
        :return: Yields a couple with the text of the Element and a list of 3-tuples \
        (key, decoded data, decoder), eventually preceded by a sequence of validation \
        or encoding errors.
        """
        if not element_data.content:  # <tag/> or <tag></tag>
            yield element_data.content
            return

        if not isinstance(converter, XMLSchemaConverter):
            converter = self.schema.get_converter(converter, **kwargs)

        errors = []
        text = None
        children = []
        level = kwargs.get('level', 0)
        indent = kwargs.get('indent', 4)
        padding = '\n' + ' ' * indent * level
        default_namespace = converter.get('')
        losslessly = converter.losslessly

        model = ModelVisitor(self)
        cdata_index = 0

        for index, (name, value) in enumerate(element_data.content):
            if isinstance(name, int):
                if not children:
                    text = padding + value if text is None else text + value + padding
                elif children[-1].tail is None:
                    children[-1].tail = padding + value
                else:
                    children[-1].tail += value + padding
                cdata_index += 1
                continue

            if not default_namespace or name[0] == '{':
                tag = name
            else:
                tag = '{%s}%s' % (default_namespace, name)

            while model.element is not None:
                if tag in model.element.names or model.element.name is None \
                        and model.element.is_matching(tag, default_namespace):
                    xsd_element = model.element
                else:
                    for xsd_element in model.element.iter_substitutes():
                        if tag in xsd_element.names:
                            break
                    else:
                        for particle, occurs, expected in model.advance():
                            errors.append((index - cdata_index, particle,
                                           occurs, expected))
                        continue

                if isinstance(xsd_element, XsdAnyElement):
                    value = get_qname(default_namespace, name), value
                for result in xsd_element.iter_encode(value, validation,
                                                      converter, **kwargs):
                    if isinstance(result, XMLSchemaValidationError):
                        yield result
                    else:
                        children.append(result)

                for particle, occurs, expected in model.advance(True):
                    errors.append(
                        (index - cdata_index, particle, occurs, expected))
                break
            else:
                if losslessly:
                    errors.append((index - cdata_index, self, 0, []))

                for xsd_element in self.iter_elements():
                    if tag in xsd_element.names or xsd_element.name is None \
                            and xsd_element.is_matching(name, default_namespace):
                        if isinstance(xsd_element, XsdAnyElement):
                            value = get_qname(default_namespace, name), value
                        for result in xsd_element.iter_encode(
                                value, validation, converter, **kwargs):
                            if isinstance(result, XMLSchemaValidationError):
                                yield result
                            else:
                                children.append(result)
                        break
                else:
                    if validation != 'skip':
                        reason = '%r does not match any declared element of the model group.' % name
                        yield self.validation_error(validation, reason, value,
                                                    **kwargs)

        if model.element is not None:
            index = len(element_data.content) - cdata_index
            for particle, occurs, expected in model.stop():
                errors.append((index, particle, occurs, expected))

        # If the validation is not strict tries to solve model errors with a reorder of the children
        if errors and validation != 'strict':
            children = self.sort_children(children, default_namespace)

        if children:
            if children[-1].tail is None:
                children[-1].tail = padding[:-indent] or '\n'
            else:
                children[-1].tail = children[-1].tail.strip() + (
                    padding[:-indent] or '\n')

        if validation != 'skip' and errors:
            attrib = {
                k: unicode_type(v)
                for k, v in element_data.attributes.items()
            }
            if validation == 'lax' and converter.etree_element_class is not etree_element:
                child_tags = [
                    converter.etree_element(e.tag, attrib=e.attrib)
                    for e in children
                ]
                elem = converter.etree_element(element_data.tag, text,
                                               child_tags, attrib)
            else:
                elem = converter.etree_element(element_data.tag, text,
                                               children, attrib)

            for index, particle, occurs, expected in errors:
                yield self.children_validation_error(validation, elem, index,
                                                     particle, occurs,
                                                     expected, **kwargs)

        yield text, children
예제 #11
0
    def _parse(self):
        super(XsdGroup, self)._parse()
        self.clear()
        elem = self.elem
        self._parse_particle(elem)

        if elem.tag == XSD_GROUP:
            # Global group (group)
            name = elem.get('name')
            ref = elem.get('ref')
            if name is None:
                if ref is not None:
                    # Reference to a global group
                    if self.parent is None:
                        self.parse_error("a group reference cannot be global")

                    try:
                        self.name = self.schema.resolve_qname(ref)
                    except ValueError as err:
                        self.parse_error(err, elem)
                        return

                    try:
                        xsd_group = self.schema.maps.lookup_group(self.name)
                    except KeyError:
                        self.parse_error("missing group %r" %
                                         self.prefixed_name)
                        xsd_group = self.schema.create_any_content_group(
                            self, self.name)

                    if isinstance(xsd_group, tuple):
                        # Disallowed circular definition, substitute with any content group.
                        self.parse_error(
                            "Circular definitions detected for group %r:" %
                            self.ref, xsd_group[0])
                        self.model = 'sequence'
                        self.mixed = True
                        self.append(
                            XsdAnyElement(ANY_ELEMENT, self.schema, self))
                    else:
                        self.model = xsd_group.model
                        if self.model == 'all':
                            if self.max_occurs != 1:
                                self.parse_error(
                                    "maxOccurs must be 1 for 'all' model groups"
                                )
                            if self.min_occurs not in (0, 1):
                                self.parse_error(
                                    "minOccurs must be (0 | 1) for 'all' model groups"
                                )
                            if self.schema.XSD_VERSION == '1.0' and isinstance(
                                    self.parent, XsdGroup):
                                self.parse_error(
                                    "in XSD 1.0 the 'all' model group cannot be nested"
                                )
                        self.append(xsd_group)
                else:
                    self.parse_error(
                        "missing both attributes 'name' and 'ref'")
                return
            elif ref is None:
                # Global group
                self.name = get_qname(self.target_namespace, name)
                content_model = self._parse_component(elem)
                if self.parent is not None:
                    self.parse_error(
                        "attribute 'name' not allowed for a local group")
                else:
                    if 'minOccurs' in elem.attrib:
                        self.parse_error(
                            "attribute 'minOccurs' not allowed for a global group"
                        )
                    if 'maxOccurs' in elem.attrib:
                        self.parse_error(
                            "attribute 'maxOccurs' not allowed for a global group"
                        )
                    if 'minOccurs' in content_model.attrib:
                        self.parse_error(
                            "attribute 'minOccurs' not allowed for the model of a global group",
                            content_model)
                    if 'maxOccurs' in content_model.attrib:
                        self.parse_error(
                            "attribute 'maxOccurs' not allowed for the model of a global group",
                            content_model)
                    if content_model.tag not in {
                            XSD_SEQUENCE, XSD_ALL, XSD_CHOICE
                    }:
                        self.parse_error(
                            'unexpected tag %r' % content_model.tag,
                            content_model)
                        return

            else:
                self.parse_error("found both attributes 'name' and 'ref'")
                return
        elif elem.tag in {XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}:
            # Local group (sequence|all|choice)
            if 'name' in elem.attrib:
                self.parse_error(
                    "attribute 'name' not allowed for a local group")
            content_model = elem
            self.name = None
        elif elem.tag in {XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_RESTRICTION}:
            self.name = self.model = None
            return
        else:
            self.parse_error('unexpected tag %r' % elem.tag, elem)
            return

        self._parse_content_model(elem, content_model)
예제 #12
0
    def _parse(self):
        super(XsdAttribute, self)._parse()
        elem = self.elem

        try:
            form = self.form
        except ValueError as err:
            self.parse_error(err)
        else:
            if form is None:
                self.qualified = self.schema.attribute_form_default == 'qualified'
            elif self.parent is None:
                self.parse_error(
                    "attribute 'form' not allowed in a global attribute.")
            else:
                self.qualified = form == 'qualified'

        self.use = elem.get('use')
        if self.use is None:
            self.use = 'optional'
        elif self.parent is None:
            self.parse_error(
                "attribute 'use' not allowed in a global attribute.")
        elif self.use not in {'optional', 'prohibited', 'required'}:
            self.parse_error("wrong value %r for 'use' attribute." % self.use)
            self.use = 'optional'

        name = elem.get('name')
        if name is not None:
            if 'ref' in elem.attrib:
                self.parse_error(
                    "both 'name' and 'ref' in attribute declaration")
            elif name == 'xmlns':
                self.parse_error(
                    "an attribute name must be different from 'xmlns'")

            if self.parent is None or self.qualified:
                if self.target_namespace == XSI_NAMESPACE and \
                        name not in {'nil', 'type', 'schemaLocation', 'noNamespaceSchemaLocation'}:
                    self.parse_error("Cannot add attributes in %r namespace" %
                                     XSI_NAMESPACE)
                self.name = get_qname(self.target_namespace, name)
            else:
                self.name = name
        elif self.parent is None:
            self.parse_error("missing 'name' in global attribute declaration")
        else:
            try:
                attribute_qname = self.schema.resolve_qname(elem.attrib['ref'])
            except KeyError:
                self.parse_error(
                    "missing both 'name' and 'ref' in attribute declaration")
                self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
                return
            except ValueError as err:
                self.parse_error(err)
                self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
                return
            else:
                try:
                    xsd_attribute = self.maps.lookup_attribute(attribute_qname)
                except LookupError:
                    self.parse_error("unknown attribute %r" %
                                     elem.attrib['ref'])
                    self.type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
                else:
                    self.type = xsd_attribute.type
                    self.qualified = xsd_attribute.qualified
                    if xsd_attribute.fixed is not None and 'fixed' in elem.attrib and \
                            elem.get('fixed') != xsd_attribute.fixed:
                        self.parse_error(
                            "referenced attribute has a different fixed value %r"
                            % xsd_attribute.fixed)

                self.name = attribute_qname
                for attribute in ('form', 'type'):
                    if attribute in self.elem.attrib:
                        self.parse_error(
                            "attribute %r is not allowed when attribute reference is used."
                            % attribute)
                xsd_declaration = self._parse_component(elem, required=False)

                if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
                    self.parse_error(
                        "not allowed type declaration for XSD attribute reference"
                    )
                return

        xsd_declaration = self._parse_component(elem, required=False)
        try:
            type_qname = self.schema.resolve_qname(elem.attrib['type'])
        except ValueError as err:
            self.parse_error(err, elem)
            xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
        except KeyError:
            if xsd_declaration is not None:
                # No 'type' attribute in declaration, parse for child local simpleType
                xsd_type = self.schema.BUILDERS.simple_type_factory(
                    xsd_declaration, self.schema, self)
            else:
                # Empty declaration means xsdAnySimpleType
                xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
        else:
            try:
                xsd_type = self.maps.lookup_type(type_qname)
            except LookupError as err:
                self.parse_error(err, elem)
                xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)

            if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
                self.parse_error(
                    "ambiguous type declaration for XSD attribute")
            elif xsd_declaration:
                self.parse_error(
                    "not allowed element in XSD attribute declaration: %r" %
                    xsd_declaration[0])

        try:
            self.type = xsd_type
        except TypeError as err:
            self.parse_error(err)

        # Check value constraints
        if 'default' in elem.attrib:
            if 'fixed' in elem.attrib:
                self.parse_error(
                    "'default' and 'fixed' attributes are mutually exclusive")
            if self.use != 'optional':
                self.parse_error(
                    "the attribute 'use' must be 'optional' if the attribute 'default' is present"
                )
            if not self.type.is_valid(elem.attrib['default']):
                msg = "'default' value {!r} is not compatible with the type {!r}"
                self.parse_error(msg.format(elem.attrib['default'], self.type))
            elif self.type.is_key():
                self.parse_error(
                    "'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'"
                )
        elif 'fixed' in elem.attrib:
            if not self.type.is_valid(elem.attrib['fixed']):
                msg = "'fixed' value {!r} is not compatible with the type {!r}"
                self.parse_error(msg.format(elem.attrib['fixed'], self.type))
            elif self.type.is_key():
                self.parse_error(
                    "'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'"
                )
예제 #13
0
    def _parse(self):
        super(XsdAttributeGroup, self)._parse()
        elem = self.elem
        any_attribute = False
        attribute_group_refs = []

        if elem.tag == XSD_ATTRIBUTE_GROUP:
            if self.parent is not None:
                return  # Skip dummy definitions
            try:
                self.name = get_qname(self.target_namespace,
                                      self.elem.attrib['name'])
            except KeyError:
                self.parse_error(
                    "an attribute group declaration requires a 'name' attribute."
                )
                return

        attributes = ordered_dict_class()
        for child in self._iterparse_components(elem):
            if any_attribute:
                if child.tag == XSD_ANY_ATTRIBUTE:
                    self.parse_error(
                        "more anyAttribute declarations in the same attribute group"
                    )
                else:
                    self.parse_error("another declaration after anyAttribute")

            elif child.tag == XSD_ANY_ATTRIBUTE:
                any_attribute = True
                attributes.update([(None,
                                    XsdAnyAttribute(child, self.schema,
                                                    self))])

            elif child.tag == XSD_ATTRIBUTE:
                attribute = self.schema.BUILDERS.attribute_class(
                    child, self.schema, self)
                if attribute.name in attributes:
                    self.parse_error(
                        "multiple declaration for attribute {!r}".format(
                            attribute.name))
                else:
                    attributes[attribute.name] = attribute

            elif child.tag == XSD_ATTRIBUTE_GROUP:
                try:
                    ref = child.attrib['ref']
                    attribute_group_qname = self.schema.resolve_qname(ref)
                except ValueError as err:
                    self.parse_error(err, elem)
                except KeyError:
                    self.parse_error(
                        "the attribute 'ref' is required in a local attributeGroup",
                        elem)
                else:
                    if attribute_group_qname in attribute_group_refs:
                        self.parse_error("duplicated attributeGroup %r" % ref)
                    elif self.redefine is not None:
                        if attribute_group_qname == self.name:
                            if attribute_group_refs:
                                self.parse_error(
                                    "in a redefinition the reference to itself must be the first"
                                )
                            attribute_group_refs.append(attribute_group_qname)
                            attributes.update(self._attribute_group.items())
                            continue
                        elif not attribute_group_refs:
                            # May be an attributeGroup restriction with a ref to another group
                            if not any(e.tag == XSD_ATTRIBUTE_GROUP
                                       and ref == e.get('ref')
                                       for e in self.redefine.elem):
                                self.parse_error(
                                    "attributeGroup ref=%r is not in the redefined group"
                                    % ref)
                    elif attribute_group_qname == self.name and self.schema.XSD_VERSION == '1.0':
                        self.parse_error(
                            "Circular attribute groups not allowed in XSD 1.0")
                    attribute_group_refs.append(attribute_group_qname)

                    try:
                        base_attributes = self.maps.lookup_attribute_group(
                            attribute_group_qname)
                    except LookupError:
                        self.parse_error(
                            "unknown attribute group %r" % child.attrib['ref'],
                            elem)
                    else:
                        if isinstance(base_attributes, tuple):
                            self.parse_error(
                                "Circular reference found between attribute groups "
                                "{!r} and {!r}".format(self.name,
                                                       attribute_group_qname))

                        for name, attr in base_attributes.items():
                            if name is not None and name in attributes:
                                self.parse_error(
                                    "multiple declaration for attribute {!r}".
                                    format(name))
                            else:
                                attributes[name] = attr

            elif self.name is not None:
                self.parse_error(
                    "(attribute | attributeGroup) expected, found %r." % child)

        # Check and copy base attributes
        if self.base_attributes is not None:
            wildcard = self.base_attributes.get(None)
            for name, attr in attributes.items():
                if name not in self.base_attributes:
                    if self.derivation != 'restriction':
                        continue
                    elif wildcard is None or not wildcard.is_matching(
                            name, self.default_namespace):
                        self.parse_error(
                            "Unexpected attribute %r in restriction" % name)
                    continue

                base_attr = self.base_attributes[name]

                if name is None:
                    if self.derivation == 'extension':
                        try:
                            attr.extend_namespace(base_attr)
                        except ValueError as err:
                            self.parse_error(err)
                    elif not attr.is_restriction(base_attr):
                        self.parse_error(
                            "Attribute wildcard is not a restriction of the base wildcard"
                        )
                    continue
                if self.derivation == 'restriction' and attr.type.name != XSD_ANY_SIMPLE_TYPE and \
                        not attr.type.is_derived(base_attr.type, 'restriction'):
                    self.parse_error(
                        "Attribute type is not a restriction of the base attribute type"
                    )
                if base_attr.use != 'optional' and attr.use == 'optional' or \
                        base_attr.use == 'required' and attr.use != 'required':
                    self.parse_error(
                        "Attribute %r: unmatched attribute use in restriction"
                        % name)
                if base_attr.fixed is not None and \
                        attr.type.normalize(attr.fixed) != base_attr.type.normalize(base_attr.fixed):
                    self.parse_error(
                        "Attribute %r: derived attribute has a different fixed value"
                        % name)

            self._attribute_group.update(self.base_attributes.items())
        elif self.redefine is not None and not attribute_group_refs:
            for name, attr in self._attribute_group.items():
                if name is None:
                    continue
                elif name not in attributes:
                    if attr.use == 'required':
                        self.parse_error(
                            "Missing required attribute %r in redefinition restriction"
                            % name)
                    continue
                if attr.use != 'optional' and attributes[name].use != attr.use:
                    self.parse_error(
                        "Attribute %r: unmatched attribute use in redefinition"
                        % name)
                if attr.fixed is not None and attributes[name].fixed is None:
                    self.parse_error(
                        "Attribute %r: redefinition remove fixed constraint" %
                        name)

            pos = 0
            keys = list(self._attribute_group.keys())
            for name in attributes:
                try:
                    next_pos = keys.index(name)
                except ValueError:
                    self.parse_error(
                        "Redefinition restriction contains additional attribute %r"
                        % name)
                else:
                    if next_pos < pos:
                        self.parse_error(
                            "Wrong attribute order in redefinition restriction"
                        )
                        break
                    pos = next_pos
            self.clear()

        self._attribute_group.update(attributes)

        if self.schema.XSD_VERSION == '1.0':
            has_key = False
            for attr in self._attribute_group.values():
                if attr.name is not None and attr.type.is_key():
                    if has_key:
                        self.parse_error(
                            "multiple key attributes in a group not allowed in XSD 1.0"
                        )
                    has_key = True

        elif self.parent is None and self.schema.default_attributes == self.name:
            self.schema.default_attributes = self