Skip to main content

Module tree

Module tree 

Source
Expand description

XML tree construction and manipulation (§17, §18, §85 Phase 1).

Complete tree construction/manipulation, namespaces, attributes, dictionaries, entity structures, document ownership, copying, linking, and freeing.

§UPSTREAM-PARITY

The libxml2 tree is an observable data structure. The pointer topology (parent, children, last, next, prev, doc, ns, properties, nsDef) is part of the compatibility contract and must be court-tested.

Key invariants (matching upstream):

  • node->doc points to the owning document (or NULL if not owned)
  • node->parent points to the parent element (or NULL for root)
  • node->children points to the first child
  • node->last points to the last child
  • node->next / node->prev form a doubly-linked list of siblings
  • node->properties points to the first attribute (for elements)
  • node->nsDef points to the first namespace declaration (for elements)
  • doc->children points to the root element
  • doc->doc points to itself (self-reference)

§Ownership model

Documents own all their nodes. When a document is freed, all nodes are freed. Nodes can be moved between documents via unlinking and re-adding.

§Phase 1 status

Complete — all tree operations are implemented. Future phases may add more edge-case handling for historical quirks.

§Upstream contract

Mirrors upstream tree.c and buf.c (SRC-LIBXML2-2.15.0, oracle tree oracle/historical/src/libxml2-2.15.0/). The tree is an observable data structure: pointer topology (parent, children, last, next, prev, doc, ns, properties, nsDef) is part of the compatibility contract and must be court-tested. Parity target: the system libxml2 2.15.3 oracle.

§Conceptual behavior

Complete tree construction/manipulation: namespaces, attributes, dictionaries, entity structures, document ownership, copying, linking and freeing. Nodes are C-layout mirrors (tree.h); copy/link/free semantics follow xmlCopyNode / xmlAddChild / xmlFreeNodeList / xmlFreeDoc.

§Ownership & safety invariants

Documents own all their nodes; freeing the document frees the subtree. node->parent, node->doc, node->ns, node->next/prev are borrowed pointers — never freed by the reader. Allocator domain: xmlMalloc, freed with xmlFree (atlas/OWNERSHIP_ATLAS.md). SAFETY: the Rust mirrors enforce layout exactly (#[repr(C)]); _xmlElement is 104 bytes upstream and must stay that size (R-000139: a 56-byte mirror under-allocated every element declaration).

§Historical quirks & epochs

QUIRK-0002 / LORE-0006: namespace nodes have no parent — a long-standing divergence upstream was aware of since the c14n fix commit 044fc6b7 (2002). E-004: entity-content text nodes became TEXT compact at 2.13.0 (commit 8d04f0ee). The 11.1-N structural alignment (R-000164) pinned doc->children DTD placement, CDATA node names, standalone=-2 and the attribute hash (name,prefix,elem) key order.

§Deliberate oddities

Deliberate oddities preserved for parity: an xmlns= declaration with an empty value yields href pointing at an empty string (not NULL), parsed attributes keep atype=0, the DTD node joins doc->children before the first element, and xmlGetLineNo returns long with the upstream -1 walk for non-element nodes (all R-000164).

§Proving courts

OWNERSHIP and TREE-STRUCTURE court families; TREE-001 (27-block structural fingerprint of 20 corpus docs x 8 option variants, byte-identical), ASan full-suite runs, and cargo test --lib (counts generated into atlas/TEST_COUNTS.json by tools/evidence/test_counts.py). Receipts under courts/receipts/phase-11.

§Tempting simplifications that would break parity

A tempting simplification is a nicer Rust node type instead of the exact _xmlNode / _xmlElement mirrors — it would break the C ABI layout (R-000139 class) and every C consumer reading fields at upstream offsets. Do not auto-maintain parent pointers for namespace nodes (QUIRK-0002); do not drop the last/next/prev links — TREE-001 fingerprints them.

§Safety

  • The unsafe entry points in this module accept raw pointers that must be valid, correctly typed, and live for the duration of the call: _xmlDoc, _xmlNode, _xmlAttr, _xmlNs, _xmlDtd, _xmlBuffer, and NUL-terminated xmlChar strings. NULL is permitted only where an individual function’s contract explicitly allows it.
  • Tree links (parent, children, last, next, prev, properties, nsDef) must form a consistent, live tree; documents own their node subtrees, so callers must not free a node that still belongs to a live document.

Functions§

add_child
Add a child node to a parent.
add_doc_entity
Add an entity declaration to the document’s internal subset (upstream entities.c xmlAddDocEntity); creates the internal subset when absent.
add_dtd_entity
Add an entity declaration to the document’s external subset (upstream entities.c xmlAddDtdEntity); creates the external subset when absent.
add_sibling
Add a sibling node after another.
add_sibling_before
Add a sibling node before another.
child_element_count
Count the child ELEMENT nodes of a node (upstream tree.c xmlChildElementCount).
copy_doc
Copy a document (deep copy by default).
copy_node
Copy a node (shallow or deep).
doc_get_root_element
Get the root element of a document.
doc_set_root_element
Set the root element of a document.
dump_doc
Dump a document to a null-terminated string.
first_element_child
Return the first child ELEMENT of a node, or NULL (upstream tree.c xmlFirstElementChild).
free_doc
Free a document and all its contents.
free_node
Free a single node (without freeing children).
free_node_list
Free a linked list of nodes.
get_doc_entity
Get a document entity by name.
get_dtd_entity
Get an entity declaration from the internal or external subset (upstream entities.c xmlGetDtdEntity).
get_int_subset
Get the internal DTD subset of a document.
get_line_no
Get the line number of a node.
get_ns_list
Get a list of namespaces in scope for a node.
get_ns_prop
Get a namespaced attribute value.
get_parameter_entity
Get a parameter entity by name.
get_prop
Get an attribute value by name.
has_ns_prop
Check whether a node has a namespaced property (upstream tree.c xmlHasNsProp): returns the attribute pointer or NULL. A NULL nameSpace matches the no-namespace case.
has_prop
Check whether a node has a property with the given name (upstream tree.c xmlHasProp): returns the attribute pointer or NULL.
last_element_child
Return the last child ELEMENT of a node, or NULL (upstream tree.c xmlLastElementChild).
new_cdata_block
Create a new CDATA section node.
new_child
Create a new child element.
new_comment
Create a new comment node.
new_doc
Create a new XML document.
new_dtd
Create a new DTD node.
new_entity
Create a new entity.
new_node
Create a new XML node.
new_node_eat_name
Create a new XML element node whose name is BORROWED (not duplicated).
new_ns
Create a new namespace declaration.
new_pi
Create a new processing instruction node.
new_text
Create a new text node.
next_element_sibling
Return the next ELEMENT sibling of a node, or NULL (upstream tree.c xmlNextElementSibling).
node_get_content
Get the content of a node, recursively concatenating child text.
previous_element_sibling
Return the previous ELEMENT sibling of a node, or NULL (upstream tree.c xmlPreviousElementSibling).
remove_prop
Remove a property from a node.
search_ns
UPSTREAM-PARITY (tree.c xmlSearchNsSafe): search for a namespace bound to the given PREFIX in scope of node. A NULL name_space searches the default namespace. The walk only ever reads ELEMENT nodes’ nsDef chains (the document is NOT an element: its oldNs list must never be mistaken for declarations), and a declaration with a NULL href does not bind its prefix.
search_ns_by_href
Search for a namespace by href (URI).
set_ns
Set the namespace of a node.
set_ns_prop
Set a namespaced attribute.
set_prop
Set an attribute on a node.
text_concat
Concatenate text to a node’s content (upstream tree.c xmlTextConcat): appends num bytes of str to the node’s text content. Returns 0 on success, -1 on error.
text_merge
Merge the text content of two nodes (upstream tree.c xmlTextMerge): appends ntext’s content to text’s content and frees ntext. Returns the first node, or NULL on error.
unlink_node
Unlink a node from its parent/siblings.
unset_ns_prop
Remove a namespaced property by name (upstream tree.c xmlUnsetNsProp).
unset_prop
Remove a property by name from a node (upstream tree.c xmlUnsetProp): returns 0 on success, -1 if the property does not exist or arguments are NULL.
xml_strlen
Get the length of a null-terminated xmlChar string.