3.3. adapter.aasx - Read and write AASX-files
Functionality for reading and writing AASX files according to “Details of the Asset Administration Shell Part 1 V2.0”, section 7.
The AASX file format is built upon the Open Packaging Conventions (OPC; ECMA 376-2). We use the pyecma376_2 library for low level OPC reading and writing. It currently supports all required features except for embedded digital signatures.
Writing and reading of AASX packages is performed through the AASXReader and AASXWriter classes.
Each instance of these classes wraps an existing AASX file resp. a file to be created and allows to read/write the
included AAS objects into/form ObjectStores.
For handling of embedded supplementary files, this module provides the
AbstractSupplementaryFileContainer class
interface and the DictSupplementaryFileContainer implementation.
- class basyx.aas.adapter.aasx.AASXReader(file: Union[os.PathLike, str, IO])
An AASXReader wraps an existing AASX package file to allow reading its contents and metadata.
Basic usage:
objects = DictObjectStore() files = DictSupplementaryFileContainer() with AASXReader("filename.aasx") as reader: meta_data = reader.get_core_properties() reader.read_into(objects, files)
- close() None
Close the AASXReader and the underlying OPC / ZIP file readers. Must be called after reading the file.
- get_core_properties() pyecma376_2.core_properties.OPCCoreProperties
Retrieve the OPC Core Properties (meta data) of the AASX package file.
If no meta data is provided in the package file, an emtpy OPCCoreProperties object is returned.
- Returns
The AASX package’s meta data
- get_thumbnail() Optional[bytes]
Retrieve the packages thumbnail image
The thumbnail image file is read into memory and returned as bytes object. You may use some python image library for further processing or conversion, e.g. pillow:
import io from PIL import Image thumbnail = Image.open(io.BytesIO(reader.get_thumbnail()))
- Returns
The AASX package thumbnail’s file contents or None if no thumbnail is provided
- read_into(object_store: basyx.aas.model.provider.AbstractObjectStore, file_store: basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer, override_existing: bool = False, **kwargs) Set[str]
Read the contents of the AASX package and add them into a given
ObjectStoreThis function does the main job of reading the AASX file’s contents. It traverses the relationships within the package to find AAS JSON or XML parts, parses them and adds the contained AAS objects into the provided object_store. While doing so, it searches all parsed
SubmodelsforFileobjects to extract the supplementary files. The referenced supplementary files are added to the given file_store and theFileobjects’ values are updated with the absolute name of the supplementary file to allow for robust resolution the file within the file_store later.- Parameters
object_store – An
ObjectStoreto add the AAS objects from the AASX file tofile_store – A
SupplementaryFileContainerto add the embedded supplementary files tooverride_existing – If True, existing objects in the object store are overridden with objects from the AASX that have the same
Identifier. Default behavior is to skip those objects from the AASX.
- Returns
A set of the
Identifiersof allIdentifiableobjects parsed from the AASX file
- class basyx.aas.adapter.aasx.AASXWriter(file: Union[os.PathLike, str, IO])
An AASXWriter wraps a new AASX package file to write its contents to it piece by piece.
Basic usage:
# object_store and file_store are expected to be given (e.g. some storage backend or previously created data) cp = OPCCoreProperties() cp.creator = "ACPLT" cp.created = datetime.datetime.now() with AASXWriter("filename.aasx") as writer: writer.write_aas("https://acplt.org/AssetAdministrationShell", object_store, file_store) writer.write_aas("https://acplt.org/AssetAdministrationShell2", object_store, file_store) writer.write_core_properties(cp)
Attention: The AASXWriter must always be closed using the
close()method or its context manager functionality (as shown above). Otherwise the resulting AASX file will lack important data structures and will not be readable.- close()
Write relationships for all data files to package and close underlying OPC package and ZIP file.
- write_aas(aas_ids: Union[str, Iterable[str]], object_store: basyx.aas.model.provider.AbstractObjectStore, file_store: basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer, write_json: bool = False) None
Convenience method to write one or more
AssetAdministrationShellswith all included and referenced objects to the AASX package according to the part name conventions from DotAAS.This method takes the AASs’
Identifiers(as aas_ids) to retrieve the AASs from the given object_store.ReferencestoSubmodelsandConceptDescriptions(via semanticId attributes) are also resolved using the object_store. All of these objects are written to an aas-spec part /aasx/data.xml or /aasx/data.json in the AASX package, compliant to the convention presented in “Details of the Asset Administration Shell”. Supplementary files which are referenced by aFileobject in any of theSubmodelsare also added to the AASX package.This method uses write_all_aas_objects() to write the AASX part.
Attention
This method must only be used once on a single AASX package. Otherwise, the /aasx/data.json (or …xml) part would be written twice to the package, hiding the first part and possibly causing problems when reading the package.
To write multiple Asset Administration Shells to a single AASX package file, call this method once, passing a list of AAS Identifiers to the aas_ids parameter.
- Parameters
aas_ids –
Identifieror Iterable ofIdentifiersof the AAS(s) to be written to the AASX fileobject_store –
ObjectStoreto retrieve theIdentifiableAAS objects (AssetAdministrationShell,ConceptDescriptionandSubmodel) fromfile_store –
SupplementaryFileContainerto retrieve supplementary files from, which are referenced byFileobjectswrite_json – If True, JSON parts are created for the AAS and each
Submodelin the AASX package file instead of XML parts. Defaults to False.
- Raises
KeyError – If one of the AAS could not be retrieved from the object store (unresolvable
SubmodelsandConceptDescriptionsare skipped, logging a warning/info message)TypeError – If one of the given AAS ids does not resolve to an AAS (but another
Identifiableobject)
- write_aas_objects(part_name: str, object_ids: Iterable[str], object_store: basyx.aas.model.provider.AbstractObjectStore, file_store: basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer, write_json: bool = False, split_part: bool = False, additional_relationships: Iterable[pyecma376_2.package_model.OPCRelationship] = ()) None
A thin wrapper around
write_all_aas_objects()to ensure downwards compatibilityThis method takes the AAS’s
Identifier(as aas_id) to retrieve it from the given object_store. If the list of written objects includesaas.model.submodel.Submodelobjects, Supplementary files which are referenced byFileobjects within those submodels, are also added to the AASX package.Attention
You must make sure to call this method or write_all_aas_objects only once per unique part_name on a single package instance.
- Parameters
part_name – Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 part name and unique within the package. The extension of the part should match the data format (i.e. ‘.json’ if write_json else ‘.xml’).
object_ids – A list of
Identifiersof the objects to be written to the AASX package. Only theseIdentifiableobjects (and includedReferableobjects) are written to the package.object_store – The objects store to retrieve the
Identifiableobjects fromfile_store – The
SupplementaryFileContainerto retrieve supplementary files from (if there are anyFileobjects within the written objects.write_json – If True, the part is written as a JSON file instead of an XML file. Defaults to False.
split_part – If True, no aas-spec relationship is added from the aasx-origin to this part. You must make sure to reference it via a aas-spec-split relationship from another aas-spec part
additional_relationships – Optional OPC/ECMA376 relationships which should originate at the AAS object part to be written, in addition to the aas-suppl relationships which are created automatically.
- write_all_aas_objects(part_name: str, objects: basyx.aas.model.provider.AbstractObjectStore[basyx.aas.model.base.Identifiable], file_store: basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer, write_json: bool = False, split_part: bool = False, additional_relationships: Iterable[pyecma376_2.package_model.OPCRelationship] = ()) None
Write all AAS objects in a given
ObjectStoreto an XML or JSON part in the AASX package and add the referenced supplementary files to the package.This method takes an
ObjectStoreand writes all contained objects into an “aas_env” part in the AASX package. If the ObjectStore includesSubmodelobjects, supplementary files which are referenced byFileobjects within those Submodels, are fetched from the file_store and added to the AASX package.Attention
You must make sure to call this method only once per unique part_name on a single package instance.
- Parameters
part_name – Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2 part name and unique within the package. The extension of the part should match the data format (i.e. ‘.json’ if write_json else ‘.xml’).
objects – The objects to be written to the AASX package. Only these Identifiable objects (and included Referable objects) are written to the package.
file_store – The SupplementaryFileContainer to retrieve supplementary files from (if there are any File objects within the written objects.
write_json – If True, the part is written as a JSON file instead of an XML file. Defaults to False.
split_part – If True, no aas-spec relationship is added from the aasx-origin to this part. You must make sure to reference it via a aas-spec-split relationship from another aas-spec part
additional_relationships – Optional OPC/ECMA376 relationships which should originate at the AAS object part to be written, in addition to the aas-suppl relationships which are created automatically.
- write_core_properties(core_properties: pyecma376_2.core_properties.OPCCoreProperties)
Write OPC Core Properties (meta data) to the AASX package file.
Attention
This method may only be called once for each AASXWriter!
- Parameters
core_properties – The OPCCoreProperties object with the meta data to be written to the package file
- write_thumbnail(name: str, data: bytearray, content_type: str)
Write an image file as thumbnail image to the AASX package.
Attention
This method may only be called once for each AASXWriter!
- Parameters
name – The OPC part name of the thumbnail part. Should not contain ‘/’ or URI-encoded ‘/’ or ‘’.
data – The image file’s binary contents to be written
content_type – OPC content type (MIME type) of the image file
- class basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer
Abstract interface for containers of supplementary files for AASs.
Supplementary files may be PDF files or other binary or textual files, referenced in a File object of an AAS by their name. They are used to provide associated documents without embedding their contents (as
Blobobject) in the AAS.A SupplementaryFileContainer keeps track of the name and content_type (MIME type) for each file. Additionally it allows to resolve name conflicts by comparing the files’ contents and providing an alternative name for a dissimilar new file. It also provides each files sha256 hash sum to allow name conflict checking in other classes (e.g. when writing AASX files).
- abstract add_file(name: str, file: IO[bytes], content_type: str) str
Add a new file to the SupplementaryFileContainer and resolve name conflicts.
The file contents must be provided as a binary file-like object to be read by the SupplementaryFileContainer. If the container already contains an equally named file, the content_type and file contents are compared (using a hash sum). In case of dissimilar files, a new unique name for the new file is computed and returned. It should be used to update in the File object of the AAS.
- Parameters
name – The file’s proposed name. Should start with a ‘/’. Should not contain URI-encoded ‘/’ or ‘’
file – A binary file-like opened for reading the file contents
content_type – The file’s content_type
- Returns
The file name as stored in the SupplementaryFileContainer. Typically name or a modified version of name to resolve conflicts.
- abstract get_content_type(name: str) str
Get a stored file’s content_type.
- Parameters
name – file name of questioned file
- Returns
The file’s content_type
- Raises
KeyError – If no file with this name is stored
- abstract get_sha256(name: str) bytes
Get a stored file content’s sha256 hash sum.
This may be used by other classes (e.g. the AASXWriter) to check for name conflicts.
- Parameters
name – file name of questioned file
- Returns
The file content’s sha256 hash sum
- Raises
KeyError – If no file with this name is stored
- abstract write_file(name: str, file: IO[bytes]) None
Retrieve a stored file’s contents by writing them into a binary writable file-like object.
- Parameters
name – file name of questioned file
file – A binary file-like object with write() method to write the file contents into
- Raises
KeyError – If no file with this name is stored
- class basyx.aas.adapter.aasx.DictSupplementaryFileContainer
SupplementaryFileContainer implementation using a dict to store the file contents in-memory.
- add_file(name: str, file: IO[bytes], content_type: str) str
Add a new file to the SupplementaryFileContainer and resolve name conflicts.
The file contents must be provided as a binary file-like object to be read by the SupplementaryFileContainer. If the container already contains an equally named file, the content_type and file contents are compared (using a hash sum). In case of dissimilar files, a new unique name for the new file is computed and returned. It should be used to update in the File object of the AAS.
- Parameters
name – The file’s proposed name. Should start with a ‘/’. Should not contain URI-encoded ‘/’ or ‘’
file – A binary file-like opened for reading the file contents
content_type – The file’s content_type
- Returns
The file name as stored in the SupplementaryFileContainer. Typically name or a modified version of name to resolve conflicts.
- get_content_type(name: str) str
Get a stored file’s content_type.
- Parameters
name – file name of questioned file
- Returns
The file’s content_type
- Raises
KeyError – If no file with this name is stored
- get_sha256(name: str) bytes
Get a stored file content’s sha256 hash sum.
This may be used by other classes (e.g. the AASXWriter) to check for name conflicts.
- Parameters
name – file name of questioned file
- Returns
The file content’s sha256 hash sum
- Raises
KeyError – If no file with this name is stored
- write_file(name: str, file: IO[bytes]) None
Retrieve a stored file’s contents by writing them into a binary writable file-like object.
- Parameters
name – file name of questioned file
file – A binary file-like object with write() method to write the file contents into
- Raises
KeyError – If no file with this name is stored
- class basyx.aas.adapter.aasx.NameFriendlyfier
A simple helper class to create unique “AAS friendly names” according to DotAAS, section 7.6.
Objects of this class store the already created friendly names to avoid name collisions within one set of names.
- get_friendly_name(identifier: str)
Generate a friendly name from an AAS identifier.
TODO: This information is outdated. The whole class is no longer needed.
According to section 7.6 of “Details of the Asset Administration Shell”, all non-alphanumerical characters are replaced with underscores. We also replace all non-ASCII characters to generate valid URIs as the result. If this replacement results in a collision with a previously generated friendly name of this NameFriendlifier, a number is appended with underscore to the friendly name.
Example:
friendlyfier = NameFriendlyfier() friendlyfier.get_friendly_name("http://example.com/AAS-a") > "http___example_com_AAS_a" friendlyfier.get_friendly_name("http://example.com/AAS+a") > "http___example_com_AAS_a_1"