diff --git a/elementpath/xpath_nodes.py b/elementpath/xpath_nodes.py index 0b91bc9..3222f4d 100644 --- a/elementpath/xpath_nodes.py +++ b/elementpath/xpath_nodes.py @@ -8,7 +8,7 @@ # @author Davide Brunato # import importlib -from collections import deque +from collections import defaultdict, deque from collections.abc import Iterator from urllib.parse import urljoin from typing import cast, Any, Optional, TYPE_CHECKING, Union @@ -1250,6 +1250,9 @@ def apply_schema(self, schema: 'AbstractSchemaProxy') -> None: delattr(root_node, '_attributes') iterators: deque[Any] = deque() + element_match_cache: defaultdict[ + int, dict[Union[str, None], Union[XsdElementProtocol, None]] + ] = defaultdict(dict) while True: for node in children: if not isinstance(node, EtreeElementNode): @@ -1268,12 +1271,15 @@ def apply_schema(self, schema: 'AbstractSchemaProxy') -> None: xsd_element = schema.get_element(node.name) elif (content := xsd_types[-1].model_group) is None: xsd_element = None + elif node.name in (sub_cache := element_match_cache[id(content)]): + xsd_element = sub_cache[node.name] else: for xsd_element in content.iter_elements(): if xsd_element.is_matching(node.name): if xsd_element.name != node.name: # a wildcard or a substitute xsd_element = schema.get_element(node.name) + sub_cache[node.name] = xsd_element break else: xsd_element = None