Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: adapter.xml: improve error messages in case of incorrect namespace declarations #192

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 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 @@ -95,7 +97,7 @@ def _element_pretty_identifier(element: etree.Element) -> str:
Returns a pretty element identifier for a given XML element.

If the prefix is known, the namespace in the element tag is replaced by the prefix.
If additionally also the sourceline is known, is is added as a suffix to name.
If additionally also the sourceline is known, it is added as a suffix to name.
For example, instead of "{http://www.admin-shell.io/aas/2/0}assetAdministrationShell" this function would return
"aas:assetAdministrationShell on line $line", if both, prefix and sourceline, are known.

Expand All @@ -104,7 +106,11 @@ def _element_pretty_identifier(element: etree.Element) -> str:
"""
identifier = element.tag
if element.prefix is not None:
identifier = element.prefix + ":" + element.tag.split("}")[1]
# Only replace the namespace by the prefix if it matches our known namespaces,
# so the replacement by the prefix doesn't mask errors such as incorrect namespaces.
namespace, tag = element.tag.split("}", 1)
if namespace[1:] in NS_MAP.values():
identifier = element.prefix + ":" + tag
if element.sourceline is not None:
identifier += f" on line {element.sourceline}"
return identifier
Expand Down Expand Up @@ -1143,13 +1149,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
Loading