1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
#
# Copyright (c), 2016-2024, SISSA (International School for Advanced Studies).
# All rights reserved.
# This file is distributed under the terms of the MIT License.
# See the file 'LICENSE' in the root directory of the present
# distribution, or http://opensource.org/licenses/MIT.
#
# @author Davide Brunato <brunato@sissa.it>
#
from collections.abc import Iterator
from typing import cast, Any, Optional, Union, TYPE_CHECKING
from elementpath import AbstractSchemaProxy, XPath2Parser, XPathSchemaContext
from elementpath.protocols import XsdTypeProtocol
from xmlschema.exceptions import XMLSchemaValueError, XMLSchemaTypeError
from xmlschema.aliases import SchemaType
from xmlschema.names import XSD_NAMESPACE
if TYPE_CHECKING:
from xmlschema.validators import XsdElement, XsdAnyElement, XsdAssert
from .mixin import XPathElement
BaseElementType = Union['XsdElement', 'XsdAnyElement', 'XsdAssert', 'XPathElement']
class XMLSchemaProxy(AbstractSchemaProxy):
"""XPath schema proxy for the *xmlschema* library."""
_schema: SchemaType
_base_element: BaseElementType
def __init__(self, schema: Optional[SchemaType] = None,
base_element: Optional[BaseElementType] = None) -> None:
if schema is None:
from xmlschema import XMLSchema10
schema = getattr(XMLSchema10, 'meta_schema', None)
assert schema is not None
super().__init__(schema, base_element)
if base_element is not None:
try:
if base_element.schema is not schema:
msg = "{} is not an element of {}"
raise XMLSchemaValueError(msg.format(base_element, schema))
except AttributeError:
raise XMLSchemaTypeError("%r is not an XsdElement" % base_element)
def bind_parser(self, parser: XPath2Parser) -> None:
parser.schema = self
parser.symbol_table = {k: v for k, v in parser.__class__.symbol_table.items()}
parser.symbol_table.update(self._schema.maps.xpath_constructors)
def get_context(self) -> XPathSchemaContext:
if self._base_element is not None:
return XPathSchemaContext(
root=self._schema.xpath_node,
namespaces=self._schema.namespaces,
item=self._base_element.xpath_node,
)
return XPathSchemaContext(self._schema.xpath_node, self._schema.namespaces)
def is_instance(self, obj: Any, type_qname: str) -> bool:
xsd_type = self._schema.maps.types[type_qname]
try:
xsd_type.encode(obj)
except ValueError:
return False
else:
return True
def cast_as(self, obj: Any, type_qname: str) -> Any:
xsd_type = self._schema.maps.types[type_qname]
return xsd_type.decode(obj)
def iter_atomic_types(self) -> Iterator[XsdTypeProtocol]:
for xsd_type in self._schema.maps.types.values():
if getattr(xsd_type, 'target_namespace', None) != XSD_NAMESPACE and \
hasattr(xsd_type, 'primitive_type'):
yield cast(XsdTypeProtocol, xsd_type)
|