Source code for xsdata.formats.dataclass.models.elements
from dataclasses import dataclass
from dataclasses import field
from enum import auto
from enum import IntEnum
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Type
from lxml.etree import QName
from xsdata.models.enums import FormType
from xsdata.models.enums import NamespaceType
from xsdata.models.enums import QNames
[docs]@dataclass(frozen=True)
class XmlVar:
"""
Dataclass field bind metadata.
:param name: field name,
:param qname: qualified local name,
:param init: field is present in the constructor arguments.
:param nillable: allow to render empty nillable elements,
:param dataclass: field type is a dataclass or a primitive type.
:param sequential: switch to sequential rendering with other sequential siblings,
:param default: default value or factory
:param types: field bind or cast types.
:param namespaces: a list of the all the possible namespaces.
"""
name: str
qname: QName
init: bool = True
nillable: bool = False
dataclass: bool = False
sequential: bool = False
default: Any = None
types: List[Type] = field(default_factory=list)
namespaces: List[str] = field(default_factory=list)
@property
def clazz(self) -> Optional[Type]:
"""Return the first type if field is bound to a dataclass."""
return self.types[0] if self.dataclass else None
@property
def is_any_type(self) -> bool:
"""Return whether or not the field type is xs:anyType."""
return False
@property
def is_attribute(self) -> bool:
"""Return whether or not the field is derived from xs:attribute."""
return False
@property
def is_attributes(self) -> bool:
"""Return whether or not the field is derived from xs:anyAttributes."""
return False
@property
def is_element(self) -> bool:
"""Return whether or not the field is derived from xs:element."""
return False
@property
def is_list(self) -> bool:
"""Return whether or not the field is a list of elements."""
return self.default is list
@property
def is_text(self) -> bool:
"""Return whether or not the field is a text element."""
return False
@property
def is_tokens(self) -> bool:
"""Return whether or not the field is a list of tokens."""
return False
@property
def is_wildcard(self) -> bool:
"""Return whether or not the field is a text element."""
return False
[docs] def matches(self, qname: QName) -> bool:
"""
Match the field qualified local name to the given qname.
Return True automatically if the local name is a wildcard.
"""
return qname in (self.qname, QNames.ALL)
[docs]@dataclass(frozen=True)
class XmlElement(XmlVar):
"""Dataclass field bind metadata for xml elements."""
@property
def is_element(self) -> bool:
return True
@property
def is_any_type(self) -> bool:
return len(self.types) == 1 and self.types[0] is object
[docs]@dataclass(frozen=True)
class XmlWildcard(XmlVar):
"""Dataclass field bind metadata for xml wildcard elements."""
@property
def is_wildcard(self) -> bool:
return True
@property
def is_any_type(self) -> bool:
return True
[docs] def matches(self, qname: QName) -> bool:
"""Match the given qname to the wildcard allowed namespaces."""
if qname == QNames.ALL:
return True
if not self.namespaces and qname.namespace is None:
return True
for namespace in self.namespaces:
if not namespace and qname.namespace is None:
return True
if namespace == qname.namespace:
return True
if namespace == NamespaceType.ANY.value:
return True
if namespace and namespace[0] == "!" and namespace[1:] != qname.namespace:
return True
return False
[docs]@dataclass(frozen=True)
class XmlAttribute(XmlVar):
"""Dataclass field bind metadata for xml attributes."""
@property
def is_attribute(self) -> bool:
return True
[docs]@dataclass(frozen=True)
class XmlAttributes(XmlVar):
"""Dataclass field bind metadata for xml wildcard attributes."""
@property
def is_attributes(self) -> bool:
return True
[docs]@dataclass(frozen=True)
class XmlText(XmlVar):
"""Dataclass field bind metadata for xml text content."""
@property
def is_tokens(self) -> bool:
return self.is_list
@property
def is_text(self) -> bool:
return True
[docs]class FindMode(IntEnum):
"""Find switches to be used to find a specific var."""
ALL = auto()
ATTRIBUTE = auto()
ATTRIBUTES = auto()
ELEMENT = auto()
TEXT = auto()
WILDCARD = auto()
NOT_WILDCARD = auto()
LIST = auto()
NOT_LIST = auto()
find_lambdas = {
FindMode.ALL: lambda x: True,
FindMode.ATTRIBUTE: lambda x: x.is_attribute,
FindMode.ATTRIBUTES: lambda x: x.is_attributes,
FindMode.ELEMENT: lambda x: x.is_element,
FindMode.TEXT: lambda x: x.is_text,
FindMode.WILDCARD: lambda x: x.is_wildcard,
FindMode.NOT_WILDCARD: lambda x: not x.is_wildcard,
FindMode.LIST: lambda x: x.is_list,
FindMode.NOT_LIST: lambda x: not x.is_list,
}