aas_core3_2.xmlcommon

Provide the primitives which the modules reading and writing XML share.

Reading means walking a stream of (event, element) tuples: checking that an element resides in the expected namespace, consuming the end element which corresponds to a start element and taking the text out of an element. Writing means framing an element. Each of these is defined here exactly once, so that neither aas_core3_2.xmlization nor the XML-RPC subset over which a JSON-able value is de/serialized carries a copy of its own.

The namespace is a constant of this module, NAMESPACE, and no argument of its primitives. This module is generated for a single meta-model, and a meta-model prescribes exactly one namespace, so there is nothing for a caller to choose.

aas_core3_2.xmlcommon.NAMESPACE = 'https://admin-shell.io/aas/3/2'

XML namespace in which all the elements of a document are expected to reside

class aas_core3_2.xmlcommon.Element(*args, **kwargs)[source]

Behave like xml.etree.ElementTree.Element().

property attrib: Optional[Mapping[str, str]]

Attributes of the element

property text: Optional[str]

Text content of the element

property tail: Optional[str]

Tail text of the element

property tag: str

Tag of the element; with a namespace provided as a {...} prefix

clear() → None[source]

Behave like xml.etree.ElementTree.Element.clear().

__init__(*args, **kwargs)
__parameters__ = ()
__subclasshook__()

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

class aas_core3_2.xmlcommon.HasIterparse(*args, **kwargs)[source]

Parse an XML document incrementally.

iterparse(source: TextIO, events: Sequence[Literal['start', 'end']]) → Iterator[Tuple[str, Element]][source]

Behave like xml.etree.ElementTree.iterparse().

__init__(*args, **kwargs)
__parameters__ = ()
__subclasshook__()

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).

class aas_core3_2.xmlcommon.ElementSegment(element: Element)[source]

Represent an element on a path to the erroneous value.

__init__(element: Element) → None[source]

Initialize with the given values.

element: Final[Element]

Erroneous element

__str__() → str[source]

Render the segment as a tag without the namespace.

We deliberately omit the namespace in the tag names. If you want to actually query with the resulting XPath, you have to insert the namespaces manually. We did not know how to include the namespace in a meaningful way, as XPath assumes namespace prefixes to be defined outside of the document. At least the path thus rendered is informative, and you should be able to descend it manually.

class aas_core3_2.xmlcommon.IndexSegment(element: Element, index: int)[source]

Represent an element in a sequence on a path to the erroneous value.

__init__(element: Element, index: int) → None[source]

Initialize with the given values.

element: Final[Element]

Erroneous element

index: Final[int]

Index of the element in the sequence, starting at zero

__str__() → str[source]

Render the segment as an element wildcard with the index.

XPath counts the elements starting at one, so we add one to index.

class aas_core3_2.xmlcommon.KeySegment(element: Element, key: str)[source]

Represent a member of an open JSON-able object on a path to the erroneous element.

Unlike an ElementSegment, which names an element prescribed by the meta-model, a key is known only at run time, and can be any string at all.

__init__(element: Element, key: str) → None[source]

Initialize with the given values.

element: Final[Element]

Element of the <member> which carries the key

key: Final[str]

Key of the member

__str__() → str[source]

Render the segment as a predicate on the <name> child element.

A JSON-able object is written as an XML-RPC <struct>, which carries the key of a member in a <name> child element instead of in an attribute, so the XPath has to match on that child element.

class aas_core3_2.xmlcommon.Path[source]

Represent the relative path to the erroneous element.

__init__() → None[source]

Initialize as an empty path.

property segments: Sequence[Union[ElementSegment, IndexSegment, KeySegment]]

Get the segments of the path.

__str__() → str[source]

Render the path as a relative XPath.

We omit the leading / so that you can easily prefix it as you need.

exception aas_core3_2.xmlcommon.DeserializationException(cause: str)[source]

Signal that the XML de-serialization could not be performed.

__init__(cause: str) → None[source]

Initialize with the given cause and an empty path.

cause: Final[str]

Human-readable explanation of the exception’s cause

path: Final[Path]

Relative path to the erroneous value

exception aas_core3_2.xmlcommon.SerializationException(cause: str)[source]

Signal that the XML serialization could not be performed.

__init__(cause: str) → None[source]

Initialize with the given cause and an empty path.

cause: Final[str]

Human-readable explanation of the exception’s cause

property path: str

Render the path to the erroneous value as a Python access expression.

The path points into the instance which you handed over for the serialization, and not into an XML document – at the point of the failure, there is no document yet. For example, .submodels[0].id tells you that the serialization broke on that.submodels[0].id.

Mind that the elements which the XML representation adds on top of the instance contribute no segment, as they correspond to no attribute access. This concerns the element enclosing the instance itself, and the element which designates the model type of the value of a property.

__str__() → str[source]

Return str(self).

aas_core3_2.xmlcommon.parse_element_tag(element: Element) → str[source]

Extract the tag name without the namespace prefix from element.

Parameters

element – whose tag without namespace we want to extract

Returns

tag name without the namespace prefix

Raise

DeserializationException if unexpected element

aas_core3_2.xmlcommon.parse_unqualified_element_tag(element: Element) → str[source]

Extract the tag name of element, which is expected to reside in no namespace at all.

Parameters

element – whose tag we want to extract

Returns

tag name

Raise

DeserializationException if unexpected element

aas_core3_2.xmlcommon.raise_if_non_whitespace_text(element: Element, expected_what: str) → None[source]

Check that element encloses no text of its own.

An element which holds other elements may still be spelled over several lines, so the whitespace between its children is text as far as xml.etree.ElementTree is concerned. Anything else is not.

Parameters
  • element – to be verified

  • expected_what – what the element was expected to enclose

Raise

DeserializationException if there is text; conforming to the convention about handling error paths, the exception path is left empty.

aas_core3_2.xmlcommon.read_next_start_element(iterator: Iterator[Tuple[str, Element]], expected_what: str) → Element[source]

Read the next start element from iterator.

Parameters
  • iterator – Input stream of (event, element) coming from xml.etree.ElementTree.iterparse() with the argument events=["start", "end"]

  • expected_what – what we expected to read, for the error messages

Raise

DeserializationException if the input ended, or if what came next was no start element; conforming to the convention about handling error paths, the exception path is left empty.

Returns

the start element

aas_core3_2.xmlcommon.raise_if_has_tail_or_attrib(element: Element) → None[source]

Check that element has no trailing text and no attributes.

Parameters

element – to be verified

Raise

DeserializationException if trailing text or attributes; conforming to the convention about handling error paths, the exception path is left empty.

aas_core3_2.xmlcommon.read_end_element(element: Element, iterator: Iterator[Tuple[str, Element]]) → Element[source]

Read the end element corresponding to the start element from iterator.

Parameters
  • element – corresponding start element

  • iterator – Input stream of (event, element) coming from xml.etree.ElementTree.iterparse() with the argument events=["start", "end"]

Raise

DeserializationException if unexpected input

aas_core3_2.xmlcommon.read_text_from_element(element: Element, iterator: Iterator[Tuple[str, Element]]) → str[source]

Extract the text from the element, and read the end element from iterator.

The element is expected to contain text. Otherwise, it is considered as unexpected input.

Parameters
  • element – start element enclosing the text

  • iterator – Input stream of (event, element) coming from xml.etree.ElementTree.iterparse() with the argument events=["start", "end"]

Raise

DeserializationException if unexpected input

aas_core3_2.xmlcommon.read_str_from_element_text(element: Element, iterator: Iterator[Tuple[str, Element]]) → str[source]

Parse the text of element as a string, and read the corresponding end element from iterator.

If there is no text, empty string is returned.

Parameters
  • element – start element

  • iterator – Input stream of (event, element) coming from xml.etree.ElementTree.iterparse() with the argument events=["start", "end"]

Raise

DeserializationException if unexpected input

Returns

parsed value

aas_core3_2.xmlcommon.XS_WHITESPACE_RE = re.compile('[ \\t\\n\\r]+')

Match a run of the whitespace characters which XSD knows

aas_core3_2.xmlcommon.collapse_whitespace(text: str) → str[source]

Normalize text the way whiteSpace="collapse" prescribes.

Every atomic XSD type except a string, and every type derived from one by restriction, fixes whiteSpace to collapse, and a schema author can not change it. A tab, a line feed and a carriage return each become a space, a run of spaces becomes one space, and the leading and trailing spaces go. Only then is the result a lexical representation to be matched.

Mind that this strips only the whitespace around the value: a space within it survives as a single space, so 2  3 becomes 2 3, which is still no number.

See: https://www.w3.org/TR/xmlschema-2/#rf-whiteSpace

Parameters

text – to be normalized

Returns

normalized text

class aas_core3_2.xmlcommon.Writer(stream: TextIO)[source]

Write the XML elements of a single document to stream.

The namespace is specified on the very first element alone, and on none of the elements which follow it, so one writer serves exactly one document.

write_end_element(name: str) → None[source]

Write the end element with the tag name name.

Parameters

name – of the element tag. Expected to contain no XML special characters.

write_start_element_in_no_namespace(name: str) → None[source]

Write the start element with the tag name name, which resides in no namespace at all.

The outermost such element undeclares the default namespace, so that the elements nested in it reside in no namespace as well and need no declaration of their own.

Parameters

name – of the element tag. Expected to contain no XML special characters.

write_end_element_in_no_namespace(name: str) → None[source]

Write the end element with the tag name name, which resides in no namespace at all.

Parameters

name – of the element tag. Expected to contain no XML special characters.

write_empty_element_in_no_namespace(name: str) → None[source]

Write the empty element with the tag name name, which resides in no namespace at all.

If it is the outermost such element, it undeclares the default namespace.

Parameters

name – of the element tag. Expected to contain no XML special characters.

__init__(stream: TextIO) → None[source]

Initialize the writer to write to stream.

The first element will include the NAMESPACE. Every other element will not have the namespace specified.

Parameters

stream – where to write to

stream: Final[TextIO]

Stream to be written to

write_start_element: Callable[[str], None]

Method pointer to be invoked for writing the start element with or without specifying a namespace (depending on the state of the writer)

write_empty_element: Callable[[str], None]

Method pointer to be invoked for writing an empty element with or without specifying a namespace (depending on the state of the writer)