These are running notes as I study how OLX is generated and parsed. Eventually, I want to clean this up and turn it into an official OLX Specification.
XBlock
class Blocklike(...): @classmethod def parse_xml(cls, node, runtime, keys): """ Use `node` to construct a new block. Arguments: node (:class:`~xml.etree.ElementTree.Element`): The xml node to parse into an xblock. runtime (:class:`.Runtime`): The runtime to use while parsing. keys (:class:`.ScopeIds`): The keys identifying where this block will store its data. """ block = runtime.construct_xblock_from_class(cls, keys) # The base implementation: child nodes become child blocks. # Or fields, if they belong to the right namespace. for child in node: if child.tag is etree.Comment: continue qname = etree.QName(child) tag = qname.localname namespace = qname.namespace if namespace == XML_NAMESPACES["option"]: cls._set_field_if_present(block, tag, child.text, child.attrib) else: block.runtime.add_node_as_child(block, child) # Attributes become fields. for name, value in list(node.items()): # lxml has no iteritems cls._set_field_if_present(block, name, value, {}) # Text content becomes "content", if such a field exists. if "content" in block.fields and block.fields["content"].scope == Scope.content: text = node.text if text: text = text.strip() if text: block.content = text return block class XBlock(Blocklike, ...): ...