Skip to content

Commit

Permalink
adapter.xml: verify declared namespaces before deserializing
Browse files Browse the repository at this point in the history
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 eclipse-basyx#190
  • Loading branch information
jkhsjdhjs committed Dec 19, 2023
1 parent d294dad commit 2946b66
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions basyx/aas/adapter/xml/xml_deserialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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]:
Expand Down

0 comments on commit 2946b66

Please sign in to comment.