Skip to main content

PostDocument

Struct PostDocument 

Source
pub struct PostDocument {
Show 13 fields pub destination: Option<String>, pub destination_directory: Option<String>, pub site_directory: Option<String>, pub source: Option<String>, pub source_directory: Option<String>, pub searchpaths: Vec<String>, pub namespaces: FxHashMap<String, String>, pub namespace_uris: FxHashMap<String, String>, pub processing_instructions: Vec<String>, pub parent_document: Option<Box<PostDocument>>, pub split_from_id: Option<String>, pub validate: bool, pub nocache: bool, /* private fields */
}
Expand description

Post-processing document: wraps an XML document with ID management, namespace tracking, XPath helpers, and a persistent cache.

Port of LaTeXML::Post::Document.

Fields§

§destination: Option<String>

Destination file path for this document.

§destination_directory: Option<String>

Destination directory (derived from destination).

§site_directory: Option<String>

Site root directory.

§source: Option<String>

Source file path.

§source_directory: Option<String>

Source directory.

§searchpaths: Vec<String>

Search paths for resources.

§namespaces: FxHashMap<String, String>

Namespace prefix → URI mapping.

§namespace_uris: FxHashMap<String, String>

URI → prefix reverse mapping.

§processing_instructions: Vec<String>

Processing instructions from the document.

§parent_document: Option<Box<PostDocument>>

Parent document (for split sub-documents).

§split_from_id: Option<String>

ID of document we were split from.

§validate: bool

Whether to validate the document.

§nocache: bool

Whether caching is disabled.

Implementations§

Source§

impl PostDocument

Source

pub fn new(doc: Document, options: PostDocumentOptions) -> Self

Create a new PostDocument wrapping an existing XML document.

Port of Post::Document::new.

Source

pub fn new_from_file( path: &str, options: PostDocumentOptions, ) -> Result<Self, String>

Create from an XML file.

Port of Post::Document::newFromFile.

Parses with XML_PARSE_HUGE (on top of the crate’s default recover/noerror/nowarning): without it, libxml2’s hard limits corrupt a multi-GB parse well before any real malformation — the per-document dictionary cap poisons the ID table (hundreds of thousands of bogus “ID X already defined” reports for ids that occur exactly once, witnessed at ~1.47 GB into the 131 MB book’s core XML) and the parse dies outright at ~1.71 GB. Post input is our own core serialization, not attacker-authored XML, so relaxing the limits is safe.

Source

pub fn new_from_string( xml: &str, options: PostDocumentOptions, ) -> Result<Self, String>

Create from an XML string.

Port of Post::Document::newFromString.

Source

pub fn new_document(&self, root: Node, destination: &str) -> Self

Create a new sub-document from an element node.

Port of Perl Post::Document::newDocument. The element is imported into a fresh XML document. Resources, processing instructions, and class attributes are copied from the parent.

Source

pub fn get_document(&self) -> &Document

Get a reference to the underlying XML document.

Source

pub fn get_document_mut(&mut self) -> &mut Document

Get a mutable reference to the underlying XML document.

Source

pub fn get_document_element(&self) -> Option<Node>

Get the document’s root element.

Source

pub fn get_source(&self) -> Option<&str>

Get the source path.

Source

pub fn get_source_directory(&self) -> &str

Get the source directory.

Source

pub fn get_search_paths(&self) -> &[String]

Get search paths.

Source

pub fn get_destination(&self) -> Option<&str>

Get the destination path.

Source

pub fn get_destination_directory(&self) -> Option<&str>

Get the destination directory.

Source

pub fn get_site_directory(&self) -> Option<&str>

Get the site directory.

Source

pub fn site_relative_destination(&self) -> Option<String>

Return destination relative to site directory.

Port of siteRelativeDestination.

Source

pub fn site_relative_pathname(&self, pathname: &str) -> Option<String>

Return a pathname relative to the site directory.

Source

pub fn get_destination_extension(&self) -> Option<String>

Get the destination file extension.

Source

pub fn to_xml_string(&self) -> String

Serialize the document to an XML string.

Source

pub fn node_to_string(&self, node: &Node) -> String

Serialize a single node (and its subtree) to an XML string. Used to re-derive raw-string features (e.g. SVG-fragment extraction) from the DOM for file-parsed input without ever materializing the whole document.

Source

pub fn processing_instructions(&self) -> &[String]

The <?latexml …?> processing instructions collected at parse time (searchpaths, loaded packages/classes, RelaxNG schema, …). Used to re-derive package-presence sniffs (e.g. package="ar5iv") from the parsed document when the raw XML string is not held in memory.

Source

pub fn stringify(&self) -> String

Source

pub fn findnodes(&self, xpath: &str) -> Vec<Node>

Find nodes matching an XPath expression.

Port of Post::Document::findnodes.

Source

pub fn findnodes_at( &self, xpath: &str, context_node: Option<&Node>, ) -> Vec<Node>

Find nodes matching an XPath expression, relative to a given context node.

Source

pub fn find_split_pages(&self, union_xpath: &str) -> Vec<Node>

Limit-safe evaluation of a --splitat page union.

make_splitpaths emits //ltx:X and //ltx:X[preceding-sibling::ltx:Y or parent::ltx:Z] arms. As XPath on a huge document the predicated arms overflow the 10M node-set ceiling (see scan_ids_and_pis), the union returns NULL, and nothing splits — the whole document stays one page and the downstream XSLT then dies on the same ceiling. Instead we parse the arms and select pages with one limit-safe walk, applying the predicates in Rust: same nodes, document order, no duplicates, as an XPath union.

Falls back to raw XPath for unions outside that grammar (custom --splitpaths), which only run on small, limit-safe documents.

Source

pub fn findnode(&self, xpath: &str) -> Option<Node>

Find the first node matching an XPath expression.

Source

pub fn findnode_at(&self, xpath: &str, context_node: &Node) -> Option<Node>

Find the first node matching an XPath expression, relative to a context node.

Source

pub fn findvalue(&self, xpath: &str) -> Option<String>

Evaluate an XPath expression and return the string value.

Source

pub fn findnodes_foreign(xpath: &str, node: &Node) -> Vec<Node>

XPath query on an arbitrary node, even if from a different document. Creates a temporary XPath context on the node’s own document.

Source

pub fn add_namespace(&mut self, prefix: &str, nsuri: &str)

Register a new namespace prefix → URI mapping.

Port of Post::Document::addNamespace.

Source

pub fn get_qname(&self, node: &Node) -> Option<String>

Get the qualified name (prefix:localname) for a node.

Port of Post::Document::getQName.

Source

pub fn qname_prefix(&self, node: &Node) -> Option<String>

Resolve a node’s namespace URI to its registered prefix without allocating a combined “prefix:localname”. Returns the prefix as an owned String (a copy of the entry in namespace_uris); callers can then match on node.get_name() separately. Useful in hot dispatch code where the format! in get_qname is the cost.

Source

pub fn is_qname(&self, node: &Node, expected: &str) -> bool

Check whether a node’s qualified name equals a fixed “prefix:localname” string without allocating a String. Fast-path for hot comparisons like is_qname(node, "ltx:XMApp") — avoids the format! in get_qname when the caller only needs a boolean answer. Falls back to allocating comparison (via get_qname) for unknown-namespace cases so semantics exactly match get_qname(node).as_deref() == Some(...).

Source

pub fn record_id(&mut self, id: &str, node: Node)

Record an ID → node mapping.

Port of Post::Document::recordID.

Source

pub fn find_node_by_id(&self, id: &str) -> Option<&Node>

Find a node by its xml:id.

Port of Post::Document::findNodeByID.

Source

pub fn idcache_len(&self) -> usize

Number of id-bearing nodes registered in this document’s idcache. This is exactly the node set Perl’s //@xml:id iterates.

Source

pub fn idcache_iter(&self) -> impl Iterator<Item = (&String, &Node)>

Iterate (id, node) for every id-bearing node in this document, in arbitrary order. Mirrors Perl’s //@xml:id traversal (per-document, so bounded by the page size rather than the global ObjectDB).

Source

pub fn uniquify_id(&mut self, baseid: &str, suffix: Option<&str>) -> String

Generate a unique ID based on baseid, optionally applying a suffix.

If the resulting ID is already used (and not marked reusable), appends alphabetic suffixes (a, b, c, …) until unique.

Port of Post::Document::uniquifyID.

Source

pub fn generate_node_id( &mut self, node: &mut Node, prefix: &str, reusable: bool, ) -> Option<String>

Generate, add, and register an xml:id for a node.

Creates a structured ID relative to the nearest parent with an ID.

Port of Post::Document::generateNodeID.

Source

pub fn add_nodes(&mut self, parent: &mut Node, data: &[NodeData])

Add nodes to parent using the recursive representation.

Port of Post::Document::addNodes.

Source

pub fn remove_nodes(&mut self, nodes: &[Node])

Remove nodes from the document, cleaning up ID caches.

Port of Post::Document::removeNodes.

Source

pub fn preremove_nodes(&mut self, nodes: &[Node])

Mark nodes as “will be removed later” — their IDs become reusable.

Port of Post::Document::preremoveNodes.

Queue an XMath subtree for unlinking at the end of post-processing.

Mirrors Perl Post.pm L373-393’s “XMath will be removed (LATER!), but mark its ids as reusable” pattern. The actual unlink happens in drain_pending_xmath_unlinks, which the post-pipeline invokes once all math-format processors have completed. Without the defer, parallel-format chains (pmml + cmml) lose the XMath subtree on the first processor’s unlink and the second processor’s mark_xm_node_visibility walks stale XMRef targets, emitting Error:expected:id Cannot find a node with xml:id=….

Drain the deferred XMath unlinks: actually detach each subtree from the document. Idempotent against multiple processors queueing the same node — the second unlink_node is a no-op on an already-detached subtree. The deferred subtrees are wrapped in DocOwnedNode to suppress libxml’s _Node::dropxmlFreeNode chain; the enclosing Document remains the sole owner. See math_processor::process_math_node for the prior in-place wrapping pattern.

Source

pub fn remove_blank_nodes(&self, node: &Node) -> u32

Remove blank (whitespace-only) text nodes that are direct children of node.

Port of Post::Document::removeBlankNodes.

Source

pub fn replace_node(&mut self, old_node: &Node, replacements: &[NodeData])

Replace node with replacements in the document.

Port of Post::Document::replaceNode.

Source

pub fn prepend_nodes(&mut self, parent: &mut Node, nodes: &[NodeData])

Prepend nodes as the first children of parent.

Port of Post::Document::prependNodes.

Source

pub fn add_ss_values(node: &mut Node, key: &str, values: &str)

Add space-separated values to an attribute, deduplicating and sorting.

Port of Post::Document::addSSValues.

Source

pub fn add_class(node: &mut Node, class: &str)

Add CSS class(es) to a node.

Port of Post::Document::addClass.

Source

pub fn mark_xm_node_visibility(&self)

Mark XMath node visibility (content vs presentation branches).

Port of Post::Document::markXMNodeVisibility.

Source

pub fn realize_xm_node_branch( &self, node: &Node, branch: XMBranch, ) -> Option<Node>

Realize an XMRef/XMDual node along a branch — Perl realizeXMNode($node, $branch) (Post.pm L1436-1450), the two-argument form.

Unlike the branchless realize_xm_node below, this loops: an XMRef is followed to its target, an XMDual is descended into the requested branch, and either may expose the other, so resolution repeats until the node is neither. A dangling idref reports the same expected:id error and yields None.

Source

pub fn realize_xm_node(&self, node: &Node) -> Option<Node>

Realize an XMRef node: follow the reference to get the “real” node.

Port of Post::Document::realizeXMNode’s one-argument form (Post.pm L1451-1456) — a single XMRef hop, leaving an XMDual alone. Callers that need a specific branch want realize_xm_node_branch.

Source

pub fn conjoin(conjunction: Conjunction, nodes: Vec<NodeData>) -> Vec<NodeData>

Join a list of nodes with a conjunction.

Port of Post::Document::conjoin.

Source

pub fn initial(string: &str, force: bool) -> String

Find the initial letter for sorting.

Port of Post::Document::initial.

Source

pub fn trim_child_nodes(node: &Node) -> Vec<Node>

Trim leading/trailing whitespace text nodes from a node’s children.

Port of Post::Document::trimChildNodes.

Source

pub fn add_navigation(&mut self, relation: &str, id: &str)

Add a navigation reference.

Port of Post::Document::addNavigation.

Source

pub fn validate(&self) -> Result<(), String>

Validate the document against its declared schema.

Port of Post::Document::validate.

Source

pub fn idcheck(&self)

Check ID consistency.

Port of Post::Document::idcheck.

Source

pub fn cache_lookup(&self, key: &str) -> Option<String>

Look up a value in the persistent cache.

Source

pub fn cache_store(&mut self, key: &str, value: &str)

Store a value in the persistent cache.

Source

pub fn cache_remove(&mut self, key: &str)

Remove a value from the persistent cache.

Trait Implementations§

Source§

impl Drop for PostDocument

Source§

fn drop(&mut self)

Rationalize Node lifetime between post-processing components. idcache entries are Node handles into the C-owned libxml Document tree — the Document owns the lifetime, Node wrappers are lookup references.

libxml 0.3.9’s _Node::drop fires xmlFreeNode(ptr) whenever the wrapper’s internal unlinked flag is true. Math processing calls unlink_node() on nodes as it replaces XMath subtrees with MathML, flipping that flag for nodes still held by idcache. The resulting drop sequence is:

  1. document: Document (declared first) → xmlFreeDoc walks the full tree including still-reachable nodes that share memory with idcache entries; freed.
  2. idcache: HashMap<String, Node> → each Node with unlinked=true fires xmlFreeNode on already-freed memory → SIGSEGV inside xmlFreeNodeList.

Fix: hand each idcache entry to DocOwnedNode (see crate::doc_owned_node), which suppresses the inner Rc’s Drop so xmlFreeNode never fires on already-freed memory. xmlFreeDoc remains the sole owner of the C node memory. Per-entry Rc control block leaks (~24 B) — bounded by per-document idcache size and reclaimed at process exit. Proper upstream fix: a public set_linked() setter on the libxml crate’s Node, which would let us relink before drop rather than leaking.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.