XML processing

The configuration concept (Chapter System configuration and Section Component configuration) of the framework relies on XML syntax. Hence, there is the need to process XML-formed data. For parsing XML data, the Xml_node and the accompanying Xml_attribute utilities are provided. Those utilities operate directly on a text buffer that contains XML data. There is no conversion step into an internal representation. This approach alleviates the need for allocating any meta data while extracting information from XML data. The XML parser is stateless.

Vice versa, the Xml_generator serves as a utility for generating XML formatted data. The scope of an XML node is represented by a lamda function. Hence, nested XML nodes can be created by nested lamda functions, which makes the structure of the XML data immediately apparent in the C++ source code. As for the Xml_node the Xml_generator does not use any internal intermediate representation of the XML data. No dynamic memory allocations are needed while generating XML-formatted output.

A typical component imports parts of its internal state from XML input, most prominently its configuration. This import is not a one-off operation but may occur multiple times during the lifetime of the component. Hence, the component is faced with the challenge of updating its internal data model from potentially changing XML input. The List_model provides a convenient and robust formalism to implement such partial model updates.

XML parsing

Genode's XML parser consists of the two classes Xml_node and Xml_attribute. Its primary use case is the provisioning of configuration information to low-level components. Consequently, it takes the following considerations into account:

Low complexity

Because the parser is implicitly used in most components, it must not be complex to keep its footprint on the trusted computing base as small as possible.

Free-standing

The parser must be able to operate without external dependencies such as a C runtime. Otherwise, each Genode-based system would inherit such dependencies.

No dynamic memory allocations

The parser should not dynamically allocate memory to be usable in resource multiplexers and runtime environments where no anonymous memory allocations are allowed (Section Component-local heap partitioning).

Robustness

The parser must be robust in the sense that it must not contain buffer overflows, infinite loops, memory corruptions, or any other defect that may make the program crash.

Other possible goals like expressive error messages, the support for more general use cases, and even the adherence to standards are deliberately subordinated. Given its low complexity, the XML parser cannot satisfy components that need advanced XML processing such as validating XML data against a DTD or schema, mutating XML nodes, or using different character encodings. In such cases, component developers may consider the use of ported 3rd-party XML parser.

Genode::Xml_attribute

Genode::Xml_node

XML generation

Genode::Xml_generator

XML-based data models

The List_model utility eases the implementation of component-internal data models created and updated from XML. The transformation is defined by the implementation of the Update_policy interface. As a low-level mechanism, the list model is not thread safe.

Genode::List_model

Genode::List_model::Update_policy

In some situations, it is convenient to keep a verbatim copy of XML input as part of the internal data model. As the Xml_node is merely a light-weight pointer into XML data, it cannot be stored when the underlying XML data is updated dynamically. Instead, the XML input must be copied into the internal data model. The Buffered_xml utility takes care of the backing-store allocation and copying of an existing Xml_node.

Genode::Buffered_xml