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 #190
  • Loading branch information
jkhsjdhjs authored and s-heppner committed Dec 19, 2023
1 parent 3031ccf commit ae4a768
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 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,12 @@
import enum

from typing import Any, Callable, Dict, IO, Iterable, Optional, Set, Tuple, Type, TypeVar
from .._generic import XML_NS_AAS, MODELLING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_TYPES_INVERSE, \
from .._generic import XML_NS_MAP, XML_NS_AAS, MODELLING_KIND_INVERSE, ASSET_KIND_INVERSE, KEY_TYPES_INVERSE, \
ENTITY_TYPES_INVERSE, IEC61360_DATA_TYPES_INVERSE, IEC61360_LEVEL_TYPES_INVERSE, KEY_TYPES_CLASSES_INVERSE, \
REFERENCE_TYPES_INVERSE, DIRECTION_INVERSE, STATE_OF_EVENT_INVERSE, QUALIFIER_KIND_INVERSE

NS_AAS = XML_NS_AAS
REQUIRED_NAMESPACES: Set[str] = {XML_NS_MAP["aas"]}

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -1196,13 +1197,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 ae4a768

Please sign in to comment.