XML De/serialization

The code that de/serializes AAS models from and to XML documents lives in the module aas_core3.xmlization.

Serialize

You serialize the AAS model to XML-encoded text by calling the function aas_core3.xmlization.to_str().

If you want the same text to be written incrementally to a typing.TextIO stream, you can use the function aas_core3.xmlization.write().

Here is an example snippet:

import aas_core3.types as aas_types
import aas_core3.xmlization as aas_xmlization

# Prepare the environment
environment = aas_types.Environment(
    submodels=[
        aas_types.Submodel(
            id="some-unique-global-identifier",
            submodel_elements=[
                aas_types.Property(
                    id_short = "some_property",
                    value_type=aas_types.DataTypeDefXSD.INT,
                    value="1984"
                )
            ]
        )
    ]
)

# Serialize to an XML-encoded string
text = aas_xmlization.to_str(environment)

print(text)

Expected output:

<environment xmlns="https://admin-shell.io/aas/3/0"><submodels><submodel><id>some-unique-global-identifier</id><submodelElements><property><idShort>some_property</idShort><valueType>xs:int</valueType><value>1984</value></property></submodelElements></submodel></submodels></environment>

De-serialize

You can de-serialize an environment from XML coming from four different sources by using different functions:

Here is a snippet which parses XML as text and then de-serializes it into an instance of Environment:

import aas_core3.xmlization as aas_xmlization

text = (
    "<environment xmlns=\"https://admin-shell.io/aas/3/0\">" +
    "<submodels><submodel>" +
    "<id>some-unique-global-identifier</id>" +
    "<submodelElements><property><idShort>someProperty</idShort>" +
    "<valueType>xs:boolean</valueType></property></submodelElements>" +
    "</submodel></submodels></environment>"
)

environment = aas_xmlization.environment_from_str(text)

for something in environment.descend():
    print(type(something))

Expected output:

<class 'aas_core3.types.Submodel'>
<class 'aas_core3.types.Property'>

You can also de-serialize other model classes other than Environment. For example, to de-serialize a submodel, you can use aas_core3.xmlization.submodel_from_str():

import aas_core3.xmlization as aas_xmlization

text = (
    "<submodel xmlns=\"https://admin-shell.io/aas/3/0\">" +
    "<id>some-unique-global-identifier</id>" +
    "<submodelElements><property><idShort>someProperty</idShort>" +
    "<valueType>xs:boolean</valueType></property></submodelElements>" +
    "</submodel>"
)

submodel = aas_xmlization.submodel_from_str(text)

for something in submodel.descend():
    print(type(something))

Expected output:

<class 'aas_core3.types.Property'>

If you do not know the model type in advance, you can use the general functions such as aas_core3.xmlization.from_str() and aas_core3.xmlization.from_file(). The model type will be determined based on the first start element. The same example above can be thus rewritten:

import aas_core3.xmlization as aas_xmlization

text = (
    "<submodel xmlns=\"https://admin-shell.io/aas/3/0\">" +
    "<id>some-unique-global-identifier</id>" +
    "<submodelElements><property><idShort>someProperty</idShort>" +
    "<valueType>xs:boolean</valueType></property></submodelElements>" +
    "</submodel>"
)

instance = aas_xmlization.from_str(text)

for something in instance.descend():
    print(type(something))

Expected output:

<class 'aas_core3.types.Property'>

Prefer the particular de-serialization (aas_core3.xmlization.submodel_from_str()) whenever you know the type in advance. The particular de-serialization function will check the actual model type for you, and you also get more precise type annotations for your downstream code.

Errors

If the XML document comes in an unexpected form, our SDK throws a aas_core3.xmlization.DeserializationException. This can happen, for example, if unexpected XML elements or XML attributes are encountered, or an expected XML element is missing.

Disregarding XML Attributes

The specification mandates to use no XML attributes, but some libraries and tools still add their own XML attributes in the XML serialization of an AAS. You need to remove them to avoid de-serialization errors.

To that end, you need to operate directly on an iterator of XML events and elements coming from xml.etree.ElementTree.iterparse(). The attributes need to be cleared as you iterate and re-yield over the iterator.

Here is an example snippet:

import io
import xml.etree.ElementTree
from typing import Tuple, Iterator

import aas_core3.xmlization as aas_xmlization

text = (
        '<?xml version="1.0" encoding="UTF-8"?>\n'
    '<environment\n'
    '    xmlns="https://admin-shell.io/aas/3/0"\n'
    '    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n'
    '    xsi:schemaLocation="https://admin-shell.io/aas/3/0/AAS.xsd">\n'
    '</environment>\n'
)

iterator = xml.etree.ElementTree.iterparse(
    io.StringIO(text),
    # The XML de-serializer needs to operate on 'start' and 'end' events.
    events=("start", "end")
)

def with_attributes_removed(
        an_iterator: Iterator[Tuple[str, xml.etree.ElementTree.Element]]
) -> Iterator[Tuple[str, xml.etree.ElementTree.Element]]:
    """
    Map the :paramref:`iterator` such that all attributes are removed.

    :param an_iterator: to be mapped
    :yield: event and element without attributes from :paramref:`iterator`
    """
    for event, element in an_iterator:
        element.attrib.clear()

        yield event, element

environment = aas_xmlization.environment_from_iterparse(
    iterator=with_attributes_removed(iterator)
)

# The attributes are lost in the subsequent serialization.
serialization = aas_xmlization.to_str(environment)

assert (
    '<environment xmlns="https://admin-shell.io/aas/3/0"/>'
    == serialization
)