This package is built on top of libxml2 and the design is significantly influenced by it. The
Node type is a proxy object that points to a C struct allocated by libxml2. There are several node-like types in libxml2 that have common fields to constitute an XML tree. These fields are always located at the first fields of struct definitions, so we can safely use them by casting a pointer to
_Node. Especially, the first field,
_private, is reserved for applications and EzXML.jl uses it to store a pointer to a
Node object. That is, a
Node object points to a node struct and the node struct keeps an opposite pointer to the
Node object. These bidirectional references are especially important in this package.
When creating a
Node object from a pointer, the constructor first checks whether there is already a proxy object pointing to the same node. If it exists, the constructor extracts the proxy object from the
_private field and then return it. Otherwise, it creates a new proxy object and stores a reference to it in
_private. As a result, proxy objects pointing to the same node in an XML document are always unique and no duplication happens. This property is fundamental to resource management.
Node object has another field called
owner that references another
Node object or the object itself. The owner node is responsible for freeing memory resources of the node object allocated by libxml2. Freeing memories is done in the
finalize_node function, which is registered using
finalizer when creating a proxy node. If a node object does not own itself, there is almost nothing to do in
finalize_node except canceling (i.e. assigning the null pointer) the
_private field. If a node object owns itself, it finalized all descendant nodes in
finalize_node. In this process, the owner node cancels all
_private fields of its descendants because their finalizer may be called after finished freeing nodes, which may result in a segmentation fault. Another important role of keeping owner reference is that it prohibits owner objects from being deallocated by Julia's garbage collecter.
owner field is not managed by libxml2, EzXML.jl needs to update the field when changing the structure of an XML tree. For example, linking a tree with another tree will lead to an inconsistent situation where descendants nodes reference different owner nodes.
update_owners! updates the owner node of a whole tree so that this situation won't happen. Therefore, functions like
unlink! update owner objects by calling this function.