From 114f42f528e6d5e587bf69501e0cfa2bc296fbe8 Mon Sep 17 00:00:00 2001
From: Paul Gerber
Date: Mon, 15 Jun 2026 17:56:56 +0200
Subject: [PATCH 1/5] adapter: Allow optional contentType in Blob and File
Currently, the JSON and XMOL deserializiers raise an error when parsing Blob or File submodels that do not include a contentType
The contentType attribute has a cardinality of 0..1 for both classes and should therefore be optional.
The implementation now aligns with this specification and defaults to None if the field is absent in the data.
---
sdk/basyx/aas/adapter/json/json_deserialization.py | 6 ++++--
sdk/basyx/aas/adapter/xml/xml_deserialization.py | 4 ++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py
index 79db2a56..1d68d277 100644
--- a/sdk/basyx/aas/adapter/json/json_deserialization.py
+++ b/sdk/basyx/aas/adapter/json/json_deserialization.py
@@ -692,8 +692,9 @@ def _construct_submodel_element_list(cls, dct: Dict[str, object], object_class=m
@classmethod
def _construct_blob(cls, dct: Dict[str, object], object_class=model.Blob) -> model.Blob:
+ content_type = _get_ts(dct, "contentType", str) if 'contentType' in dct else None
ret = object_class(id_short=None,
- content_type=_get_ts(dct, "contentType", str))
+ content_type=content_type)
cls._amend_abstract_attributes(ret, dct)
if 'value' in dct:
ret.value = base64.b64decode(_get_ts(dct, 'value', str))
@@ -701,9 +702,10 @@ def _construct_blob(cls, dct: Dict[str, object], object_class=model.Blob) -> mod
@classmethod
def _construct_file(cls, dct: Dict[str, object], object_class=model.File) -> model.File:
+ content_type = _get_ts(dct, "contentType", str) if 'contentType' in dct else None
ret = object_class(id_short=None,
value=None,
- content_type=_get_ts(dct, "contentType", str))
+ content_type=content_type)
cls._amend_abstract_attributes(ret, dct)
if 'value' in dct and dct['value'] is not None:
ret.value = _get_ts(dct, 'value', str)
diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
index 2330b9af..e927addd 100644
--- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py
+++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
@@ -804,7 +804,7 @@ def construct_basic_event_element(cls, element: etree._Element, object_class=mod
def construct_blob(cls, element: etree._Element, object_class=model.Blob, **_kwargs: Any) -> model.Blob:
blob = object_class(
None,
- _child_text_mandatory(element, NS_AAS + "contentType")
+ _get_text_or_none(element.find(NS_AAS + "contentType"))
)
value = _get_text_or_none(element.find(NS_AAS + "value"))
if value is not None:
@@ -851,7 +851,7 @@ def construct_entity(cls, element: etree._Element, object_class=model.Entity, **
def construct_file(cls, element: etree._Element, object_class=model.File, **_kwargs: Any) -> model.File:
file = object_class(
None,
- _child_text_mandatory(element, NS_AAS + "contentType")
+ _get_text_or_none(element.find(NS_AAS + "contentType"))
)
value = _get_text_or_none(element.find(NS_AAS + "value"))
if value is not None:
From 65f2d9c6af2dc17befe8d5ca41d4203928056b81 Mon Sep 17 00:00:00 2001
From: Paul Gerber
Date: Thu, 18 Jun 2026 15:32:56 +0200
Subject: [PATCH 2/5] fix(adapter): allow optional 'valueId' in
'ValueReferencePair' for JSON and XML
---
sdk/basyx/aas/adapter/json/json_deserialization.py | 4 +++-
sdk/basyx/aas/adapter/xml/xml_deserialization.py | 5 +++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py
index 1d68d277..6a3f50ee 100644
--- a/sdk/basyx/aas/adapter/json/json_deserialization.py
+++ b/sdk/basyx/aas/adapter/json/json_deserialization.py
@@ -425,8 +425,10 @@ def _construct_value_list(cls, dct: Dict[str, object]) -> model.ValueList:
@classmethod
def _construct_value_reference_pair(cls, dct: Dict[str, object],
object_class=model.ValueReferencePair) -> model.ValueReferencePair:
+ value_id_dict = dct.get('valueId')
+ value_id = cls._construct_reference(value_id_dict) if value_id_dict is not None else None
return object_class(value=_get_ts(dct, 'value', str),
- value_id=cls._construct_reference(_get_ts(dct, 'valueId', dict)))
+ value_id=value_id)
# #############################################################################
# Direct Constructor Methods (for classes with `modelType`) starting from here
diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
index e927addd..e09d7006 100644
--- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py
+++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
@@ -1063,9 +1063,10 @@ def construct_submodel(cls, element: etree._Element, object_class=model.Submodel
@classmethod
def construct_value_reference_pair(cls, element: etree._Element, object_class=model.ValueReferencePair,
**_kwargs: Any) -> model.ValueReferencePair:
+ value_id_element = element.find(NS_AAS + "valueId")
+ value_id = cls.construct_reference(value_id_element, **_kwargs) if value_id_element is not None else None
return object_class(_child_text_mandatory(element, NS_AAS + "value"),
- _child_construct_mandatory(element, NS_AAS + "valueId", cls.construct_reference))
-
+ value_id)
@classmethod
def construct_value_list(cls, element: etree._Element, **_kwargs: Any) -> model.ValueList:
"""
From 0330a7b0123b9b9a21e601e7003226a044f8ff34 Mon Sep 17 00:00:00 2001
From: Paul Gerber
Date: Thu, 18 Jun 2026 15:58:49 +0200
Subject: [PATCH 3/5] Fix type hinting for valueId
---
sdk/basyx/aas/adapter/json/json_deserialization.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py
index 6a3f50ee..1af59106 100644
--- a/sdk/basyx/aas/adapter/json/json_deserialization.py
+++ b/sdk/basyx/aas/adapter/json/json_deserialization.py
@@ -425,10 +425,9 @@ def _construct_value_list(cls, dct: Dict[str, object]) -> model.ValueList:
@classmethod
def _construct_value_reference_pair(cls, dct: Dict[str, object],
object_class=model.ValueReferencePair) -> model.ValueReferencePair:
- value_id_dict = dct.get('valueId')
- value_id = cls._construct_reference(value_id_dict) if value_id_dict is not None else None
return object_class(value=_get_ts(dct, 'value', str),
- value_id=value_id)
+ value_id=cls._construct_reference(_get_ts(dct, 'valueId', dict))
+ if 'valueId' in dct else None)
# #############################################################################
# Direct Constructor Methods (for classes with `modelType`) starting from here
From 1bc439beb4576f7be8407b403405c24b9e3ac967 Mon Sep 17 00:00:00 2001
From: Paul Gerber
Date: Thu, 18 Jun 2026 16:03:41 +0200
Subject: [PATCH 4/5] fix whitespace issues
---
sdk/basyx/aas/adapter/xml/xml_deserialization.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
index e09d7006..0bb0abd9 100644
--- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py
+++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
@@ -1064,9 +1064,10 @@ def construct_submodel(cls, element: etree._Element, object_class=model.Submodel
def construct_value_reference_pair(cls, element: etree._Element, object_class=model.ValueReferencePair,
**_kwargs: Any) -> model.ValueReferencePair:
value_id_element = element.find(NS_AAS + "valueId")
- value_id = cls.construct_reference(value_id_element, **_kwargs) if value_id_element is not None else None
+ value_id = cls.construct_reference(value_id_element, **_kwargs) if value_id_element is not None else None
return object_class(_child_text_mandatory(element, NS_AAS + "value"),
value_id)
+
@classmethod
def construct_value_list(cls, element: etree._Element, **_kwargs: Any) -> model.ValueList:
"""
From c4bb9d9598dc83cf787f34715dd06860f1a6d9f5 Mon Sep 17 00:00:00 2001
From: Paul Gerber
Date: Thu, 18 Jun 2026 16:07:48 +0200
Subject: [PATCH 5/5] fix whitespace issues again
---
sdk/basyx/aas/adapter/xml/xml_deserialization.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
index 0bb0abd9..c231e142 100644
--- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py
+++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py
@@ -1067,7 +1067,7 @@ def construct_value_reference_pair(cls, element: etree._Element, object_class=mo
value_id = cls.construct_reference(value_id_element, **_kwargs) if value_id_element is not None else None
return object_class(_child_text_mandatory(element, NS_AAS + "value"),
value_id)
-
+
@classmethod
def construct_value_list(cls, element: etree._Element, **_kwargs: Any) -> model.ValueList:
"""