From 9dbae182436dffd1ca057eff664912fbeff58e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20M=C3=B6ller?= Date: Tue, 19 Dec 2023 13:17:49 +0100 Subject: [PATCH] adapter.xml: verify declared namespaces before deserializing Previously, if the elements of an XML document are part of an unknown namespace, this would lead to cryptic error messages such as: Unexpected top-level list aas:assetAdministrationShells on line 3 where, the correct expected element is indeed aas:assetAdministrationShells, leaving the user wondering about what could possibly be wrong. The only difference is the namespace, which isn't part of the error message, because it gets replaced by the prefix. To improve the error messages in this case, a check that compares the namespaces declared on the document against the ones required by the deserialization, and errors if a required namespace isn't declared. Partially fix https://github.com/eclipse-basyx/basyx-python-sdk/issues/190 --- basyx/aas/adapter/xml/xml_deserialization.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/basyx/aas/adapter/xml/xml_deserialization.py b/basyx/aas/adapter/xml/xml_deserialization.py index 5d4030698..535d029a4 100644 --- a/basyx/aas/adapter/xml/xml_deserialization.py +++ b/basyx/aas/adapter/xml/xml_deserialization.py @@ -49,11 +49,13 @@ import enum from typing import Any, Callable, Dict, IO, Iterable, Optional, Set, Tuple, Type, TypeVar -from .xml_serialization import NS_AAS, NS_ABAC, NS_IEC +from .xml_serialization import NS_MAP, NS_AAS, NS_ABAC, NS_IEC from .._generic import MODELING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_ELEMENTS_INVERSE, KEY_TYPES_INVERSE, \ IDENTIFIER_TYPES_INVERSE, ENTITY_TYPES_INVERSE, IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, \ KEY_ELEMENTS_CLASSES_INVERSE +REQUIRED_NAMESPACES: Set[str] = {NS_MAP["aas"]} + logger = logging.getLogger(__name__) T = TypeVar("T") @@ -1143,13 +1145,22 @@ def _parse_xml_document(file: IO, failsafe: bool = True, **parser_kwargs: Any) - parser = etree.XMLParser(remove_blank_text=True, remove_comments=True, **parser_kwargs) try: - return etree.parse(file, parser).getroot() + root = etree.parse(file, parser).getroot() except etree.XMLSyntaxError as e: if failsafe: logger.error(e) return None raise e + missing_namespaces: Set[str] = REQUIRED_NAMESPACES - set(root.nsmap.values()) + if missing_namespaces: + error_message = f"The following required namespaces are not declared: {' | '.join(missing_namespaces)}" \ + + " - Is the input document of an older version?" + if not failsafe: + raise KeyError(error_message) + logger.error(error_message) + return root + def _select_decoder(failsafe: bool, stripped: bool, decoder: Optional[Type[AASFromXmlDecoder]]) \ -> Type[AASFromXmlDecoder]: