diff --git a/basyx/aas/adapter/json/aasJSONSchema.json b/basyx/aas/adapter/json/aasJSONSchema.json index 8d77c7aac..c9f5fa22a 100644 --- a/basyx/aas/adapter/json/aasJSONSchema.json +++ b/basyx/aas/adapter/json/aasJSONSchema.json @@ -45,6 +45,15 @@ "revision": { "type": "string", "minLength": 1 + }, + "creator": { + "$ref": "#/definitions/Reference" + }, + "templateId": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "pattern": "^([\\t\\n\\r -\ud7ff\ue000-\ufffd]|\\ud800[\\udc00-\\udfff]|[\\ud801-\\udbfe][\\udc00-\\udfff]|\\udbff[\\udc00-\\udfff])*$" } } } diff --git a/basyx/aas/adapter/json/json_deserialization.py b/basyx/aas/adapter/json/json_deserialization.py index a6756957b..40820ac4c 100644 --- a/basyx/aas/adapter/json/json_deserialization.py +++ b/basyx/aas/adapter/json/json_deserialization.py @@ -356,6 +356,10 @@ def _construct_administrative_information( ret.revision = _get_ts(dct, 'revision', str) elif 'revision' in dct: logger.warning("Ignoring 'revision' attribute of AdministrativeInformation object due to missing 'version'") + if 'creator' in dct: + ret.creator = cls._construct_reference(_get_ts(dct, 'creator', dict)) + if 'templateId' in dct: + ret.template_id = _get_ts(dct, 'templateId', str) return ret @classmethod diff --git a/basyx/aas/adapter/json/json_serialization.py b/basyx/aas/adapter/json/json_serialization.py index 96dfa3532..4a79290ac 100644 --- a/basyx/aas/adapter/json/json_serialization.py +++ b/basyx/aas/adapter/json/json_serialization.py @@ -186,6 +186,10 @@ def _administrative_information_to_json(cls, obj: model.AdministrativeInformatio data['version'] = obj.version if obj.revision: data['revision'] = obj.revision + if obj.creator: + data['creator'] = obj.creator + if obj.template_id: + data['templateId'] = obj.template_id return data @classmethod diff --git a/basyx/aas/adapter/xml/AAS.xsd b/basyx/aas/adapter/xml/AAS.xsd index d2f6759cd..66364120b 100644 --- a/basyx/aas/adapter/xml/AAS.xsd +++ b/basyx/aas/adapter/xml/AAS.xsd @@ -17,6 +17,15 @@ + + + + + + + + + diff --git a/basyx/aas/adapter/xml/xml_deserialization.py b/basyx/aas/adapter/xml/xml_deserialization.py index b8e441230..f933bd58b 100644 --- a/basyx/aas/adapter/xml/xml_deserialization.py +++ b/basyx/aas/adapter/xml/xml_deserialization.py @@ -600,8 +600,12 @@ def construct_administrative_information(cls, element: etree.Element, object_cla **_kwargs: Any) -> model.AdministrativeInformation: administrative_information = object_class( revision=_get_text_or_none(element.find(NS_AAS + "revision")), - version=_get_text_or_none(element.find(NS_AAS + "version")) + version=_get_text_or_none(element.find(NS_AAS + "version")), + template_id=_get_text_or_none(element.find(NS_AAS + "templateId")) ) + creator = _failsafe_construct(element.find(NS_AAS + "creator"), cls.construct_reference, cls.failsafe) + if creator is not None: + administrative_information.creator = creator cls._amend_abstract_attributes(administrative_information, element) return administrative_information diff --git a/basyx/aas/adapter/xml/xml_serialization.py b/basyx/aas/adapter/xml/xml_serialization.py index 51c9c6d9a..987cc1e56 100644 --- a/basyx/aas/adapter/xml/xml_serialization.py +++ b/basyx/aas/adapter/xml/xml_serialization.py @@ -184,6 +184,10 @@ def administrative_information_to_xml(obj: model.AdministrativeInformation, et_administration.append(_generate_element(name=NS_AAS + "version", text=obj.version)) if obj.revision: et_administration.append(_generate_element(name=NS_AAS + "revision", text=obj.revision)) + if obj.creator: + et_administration.append(reference_to_xml(obj.creator, tag=NS_AAS + "creator")) + if obj.template_id: + et_administration.append(_generate_element(name=NS_AAS + "templateId", text=obj.template_id)) return et_administration diff --git a/basyx/aas/examples/data/example_aas.py b/basyx/aas/examples/data/example_aas.py index 6a422f8b6..499597209 100644 --- a/basyx/aas/examples/data/example_aas.py +++ b/basyx/aas/examples/data/example_aas.py @@ -193,7 +193,14 @@ def create_example_asset_identification_submodel() -> model.Submodel: 'de': 'Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung'}), parent=None, administration=model.AdministrativeInformation(version='9', - revision='0'), + revision='0', + creator=model.GlobalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'TestAsset/Identification'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/TestAsset/Identification'), semantic_id=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/SubmodelTemplates/AssetIdentification'),), model.Submodel), @@ -313,7 +320,9 @@ def create_example_bill_of_material_submodel() -> model.Submodel: description=model.LangStringSet({'en-US': 'An example bill of material submodel for the test application', 'de': 'Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='9'), + administration=model.AdministrativeInformation(version='9', + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/TestAsset/BillOfMaterial'), semantic_id=model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='http://acplt.org/SubmodelTemplates/BillOfMaterial'),), model.Submodel), @@ -703,7 +712,12 @@ def create_example_submodel() -> model.Submodel: 'de': 'Ein Beispiel-Teilmodell für eine Test-Anwendung'}), parent=None, administration=model.AdministrativeInformation(version='9', - revision='0'), + revision='0', + creator=model.GlobalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_Submodel'), + )),), semantic_id=model.GlobalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, value='http://acplt.org/SubmodelTemplates/' 'ExampleSubmodel'),)), @@ -732,7 +746,15 @@ def create_example_concept_description() -> model.ConceptDescription: description=model.LangStringSet({'en-US': 'An example concept description for the test application', 'de': 'Ein Beispiel-ConceptDescription für eine Test-Anwendung'}), parent=None, - administration=model.AdministrativeInformation(version='9', revision='0', + administration=model.AdministrativeInformation(version='9', + revision='0', + creator=model.GlobalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_ConceptDescription'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/Test_ConceptDescription', embedded_data_specifications=( _embedded_data_specification_iec61360, )), @@ -778,7 +800,14 @@ def create_example_asset_administration_shell() -> \ 'de': 'Ein Beispiel-Verwaltungsschale für eine Test-Anwendung'}), parent=None, administration=model.AdministrativeInformation(version='9', - revision='0'), + revision='0', + creator=model.GlobalReference(( + model.Key(model.KeyTypes.GLOBAL_REFERENCE, + 'http://acplt.org/AdministrativeInformation/' + 'Test_AssetAdministrationShell'), + )), + template_id='http://acplt.org/AdministrativeInformation' + 'Templates/Test_AssetAdministrationShell'), submodel={model.ModelReference((model.Key(type_=model.KeyTypes.SUBMODEL, value='https://acplt.org/Test_Submodel'),), model.Submodel, diff --git a/basyx/aas/model/base.py b/basyx/aas/model/base.py index 9dedc6e91..80c80e0cf 100644 --- a/basyx/aas/model/base.py +++ b/basyx/aas/model/base.py @@ -1094,6 +1094,7 @@ def __init__( @_string_constraints.constrain_version_type("version") +@_string_constraints.constrain_identifier("template_id") class AdministrativeInformation(HasDataSpecification): """ Administrative meta-information for an element like version information. @@ -1103,6 +1104,17 @@ class AdministrativeInformation(HasDataSpecification): :ivar version: Version of the element. :ivar revision: Revision of the element. + :ivar creator: The subject ID of the subject responsible for making the element + :ivar template_id: Identifier of the template that guided the creation of the element + + *Note:* In case of a submodel, the template ID is the identifier of the submodel template that guided the + creation of the submodel. + + *Note:* The submodel template ID is not relevant for validation. Here, the Submodel/semanticId shall be used + + *Note:* Usage of the template ID is not restricted to submodel instances. + The creation of submodel templates can also be guided by another submodel template. + :ivar embedded_data_specifications: List of Embedded data specification. used by the element. """ @@ -1110,6 +1122,8 @@ class AdministrativeInformation(HasDataSpecification): def __init__(self, version: Optional[VersionType] = None, revision: Optional[RevisionType] = None, + creator: Optional[Reference] = None, + template_id: Optional[Identifier] = None, embedded_data_specifications: Iterable[EmbeddedDataSpecification] = ()): """ Initializer of AdministrativeInformation @@ -1122,6 +1136,8 @@ def __init__(self, self.version: Optional[VersionType] = version self._revision: Optional[RevisionType] self.revision = revision + self.creator: Optional[Reference] = creator + self.template_id: Optional[Identifier] = template_id self.embedded_data_specifications: List[EmbeddedDataSpecification] = list(embedded_data_specifications) def _get_revision(self): @@ -1140,10 +1156,14 @@ def _set_revision(self, revision: Optional[RevisionType]): def __eq__(self, other) -> bool: if not isinstance(other, AdministrativeInformation): return NotImplemented - return self.version == other.version and self._revision == other._revision + return self.version == other.version \ + and self._revision == other._revision \ + and self.creator == other.creator \ + and self.template_id == other.template_id def __repr__(self) -> str: - return "AdministrativeInformation(version={}, revision={})".format(self.version, self.revision) + return "AdministrativeInformation(version={}, revision={}, creator={}, template_id={})".format( + self.version, self.revision, self.creator, self.template_id) @_string_constraints.constrain_identifier("id") diff --git a/test/compliance_tool/files/test_demo_full_example.json b/test/compliance_tool/files/test_demo_full_example.json index 0bd28746d..897185b63 100644 --- a/test/compliance_tool/files/test_demo_full_example.json +++ b/test/compliance_tool/files/test_demo_full_example.json @@ -16,7 +16,17 @@ "id": "https://acplt.org/Test_AssetAdministrationShell", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell" }, "derivedFrom": { "type": "ModelReference", @@ -322,7 +332,17 @@ "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/TestAsset/Identification" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification" }, "semanticId": { "type": "ModelReference", @@ -488,7 +508,8 @@ "modelType": "Submodel", "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", "administration": { - "version": "9" + "version": "9", + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial" }, "semanticId": { "type": "ModelReference", @@ -760,7 +781,16 @@ "id": "https://acplt.org/Test_Submodel", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_Submodel" + } + ] + } }, "semanticId": { "type": "GlobalReference", @@ -3086,6 +3116,16 @@ "administration": { "version": "9", "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_ConceptDescription" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription", "embeddedDataSpecifications": [ { "dataSpecification": { diff --git a/test/compliance_tool/files/test_demo_full_example.xml b/test/compliance_tool/files/test_demo_full_example.xml index ca16d9aef..d13b2c0da 100644 --- a/test/compliance_tool/files/test_demo_full_example.xml +++ b/test/compliance_tool/files/test_demo_full_example.xml @@ -16,6 +16,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell https://acplt.org/Test_AssetAdministrationShell @@ -308,6 +318,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification http://acplt.org/Submodels/Assets/TestAsset/Identification Instance @@ -472,6 +492,7 @@ 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial Instance @@ -638,6 +659,15 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + https://acplt.org/Test_Submodel Instance @@ -3031,6 +3061,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription https://acplt.org/Test_ConceptDescription diff --git a/test/compliance_tool/files/test_demo_full_example_json.aasx b/test/compliance_tool/files/test_demo_full_example_json.aasx index 963b156f7..e961c7eb4 100644 Binary files a/test/compliance_tool/files/test_demo_full_example_json.aasx and b/test/compliance_tool/files/test_demo_full_example_json.aasx differ diff --git a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json index 832336123..7de93fad6 100644 --- a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json +++ b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.json @@ -16,7 +16,17 @@ "id": "https://acplt.org/Test_AssetAdministrationShell", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell" }, "derivedFrom": { "type": "ModelReference", @@ -322,7 +332,17 @@ "id": "http://acplt.org/Submodels/Assets/TestAsset/Identification", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/TestAsset/Identification" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification" }, "semanticId": { "type": "ModelReference", @@ -488,7 +508,8 @@ "modelType": "Submodel", "id": "http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial", "administration": { - "version": "9" + "version": "9", + "templateId": "http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial" }, "semanticId": { "type": "ModelReference", @@ -760,7 +781,16 @@ "id": "https://acplt.org/Test_Submodel", "administration": { "version": "9", - "revision": "0" + "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_Submodel" + } + ] + } }, "semanticId": { "type": "GlobalReference", @@ -3086,6 +3116,16 @@ "administration": { "version": "9", "revision": "0", + "creator": { + "type": "GlobalReference", + "keys": [ + { + "type": "GlobalReference", + "value": "http://acplt.org/AdministrativeInformation/Test_ConceptDescription" + } + ] + }, + "templateId": "http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription", "embeddedDataSpecifications": [ { "dataSpecification": { diff --git a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml index af9ae65be..7625ef26f 100644 --- a/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml +++ b/test/compliance_tool/files/test_demo_full_example_wrong_attribute.xml @@ -16,6 +16,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_AssetAdministrationShell + + + + http://acplt.org/AdministrativeInformationTemplates/Test_AssetAdministrationShell https://acplt.org/Test_AssetAdministrationShell @@ -308,6 +318,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/TestAsset/Identification + + + + http://acplt.org/AdministrativeInformationTemplates/TestAsset/Identification http://acplt.org/Submodels/Assets/TestAsset/Identification Instance @@ -472,6 +492,7 @@ 9 + http://acplt.org/AdministrativeInformationTemplates/TestAsset/BillOfMaterial http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial Instance @@ -638,6 +659,15 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_Submodel + + + https://acplt.org/Test_Submodel Instance @@ -3031,6 +3061,16 @@ 9 0 + + GlobalReference + + + GlobalReference + http://acplt.org/AdministrativeInformation/Test_ConceptDescription + + + + http://acplt.org/AdministrativeInformationTemplates/Test_ConceptDescription https://acplt.org/Test_ConceptDescription diff --git a/test/compliance_tool/files/test_demo_full_example_xml.aasx b/test/compliance_tool/files/test_demo_full_example_xml.aasx index 87e317115..8a378350a 100644 Binary files a/test/compliance_tool/files/test_demo_full_example_xml.aasx and b/test/compliance_tool/files/test_demo_full_example_xml.aasx differ diff --git a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute.aasx b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute.aasx index faca6a196..627426cbd 100644 Binary files a/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute.aasx and b/test/compliance_tool/files/test_demo_full_example_xml_wrong_attribute.aasx differ