Skip to main content

tinyxml2/
document.rs

1//! XML document container and DOM tree manipulation.
2
3use alloc::format;
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6use core::{fmt, str};
7
8use crate::ParseOptions;
9use crate::arena::{Arena, NodeId};
10use crate::error::{Result, XmlError};
11use crate::node::{Attribute, ElementData, NodeData, NodeKind, TextData};
12use crate::parser::Parser;
13
14/// The main XML document container.
15///
16/// Owns the node arena, root node, and tracks the current parse state/error.
17#[derive(Debug)]
18pub struct Document {
19    pub(crate) arena: Arena<NodeData>,
20    root: NodeId,
21    error: Option<XmlError>,
22    options: ParseOptions,
23    has_bom: bool,
24}
25
26impl Document {
27    /// Creates a new, empty XML document containing only a root Document node.
28    #[must_use]
29    pub fn new() -> Self {
30        let mut arena = Arena::new();
31        let root = arena.alloc(NodeData::new(NodeKind::Document, 1));
32        Self {
33            arena,
34            root,
35            error: None,
36            options: ParseOptions::default(),
37            has_bom: false,
38        }
39    }
40
41    /// Creates a new, empty XML document with custom parse options.
42    #[must_use]
43    pub fn with_options(options: ParseOptions) -> Self {
44        let mut arena = Arena::new();
45        let root = arena.alloc(NodeData::new(NodeKind::Document, 1));
46        Self {
47            arena,
48            root,
49            error: None,
50            options,
51            has_bom: false,
52        }
53    }
54
55    /// Returns the root `NodeId` of the document.
56    #[must_use]
57    pub const fn root(&self) -> NodeId {
58        self.root
59    }
60
61    /// Returns the kind of the specified node, if it exists.
62    #[must_use]
63    pub fn node_kind(&self, node: NodeId) -> Option<&NodeKind> {
64        self.arena.get(node).map(|d| &d.kind)
65    }
66
67    /// Returns the 1-based source line number where this node was parsed.
68    #[must_use]
69    pub fn line_num(&self, node: NodeId) -> Option<u32> {
70        self.arena.get(node).map(|d| d.line_num)
71    }
72
73    /// Returns the current error state of the document, if any.
74    #[must_use]
75    pub fn error(&self) -> Option<XmlError> {
76        self.error.clone()
77    }
78
79    /// Returns the line number of the last error, if available.
80    #[must_use]
81    pub fn error_line(&self) -> Option<u32> {
82        self.error.as_ref().and_then(XmlError::line)
83    }
84
85    /// Sets the error state of the document.
86    pub(crate) fn set_error(&mut self, err: XmlError) {
87        self.error = Some(err);
88    }
89
90    /// Resets the document to an empty state, invalidating all existing `NodeId`s.
91    pub fn clear(&mut self) {
92        self.arena.clear();
93        self.error = None;
94        self.has_bom = false;
95        self.root = self.arena.alloc(NodeData::new(NodeKind::Document, 1));
96    }
97
98    /// Returns whether a Byte Order Mark (BOM) was detected during parsing.
99    #[must_use]
100    pub const fn has_bom(&self) -> bool {
101        self.has_bom
102    }
103
104    /// Sets whether to output a Byte Order Mark (BOM) when serializing.
105    pub fn set_bom(&mut self, use_bom: bool) {
106        self.has_bom = use_bom;
107    }
108
109    /// Returns a reference to the document's parse options.
110    #[must_use]
111    pub const fn options(&self) -> &ParseOptions {
112        &self.options
113    }
114
115    /// Returns a mutable reference to the document's parse options.
116    pub fn options_mut(&mut self) -> &mut ParseOptions {
117        &mut self.options
118    }
119
120    // --- Parsing Entry Points ---
121
122    /// Parses an XML document from a string slice in place.
123    ///
124    /// Any existing DOM structure is cleared.
125    pub fn parse_str(&mut self, xml: &str) -> Result<()> {
126        self.clear();
127
128        // Truncate at first null byte to match C++ null-terminated behavior
129        let truncated_xml = xml.split('\0').next().unwrap_or("");
130
131        // Detect and skip BOM
132        let (xml_after_bom, had_bom) = crate::util::strip_bom(truncated_xml);
133        self.has_bom = had_bom;
134
135        let mut parser = Parser::new(xml_after_bom, self.options.clone());
136        match parser.parse_document(self) {
137            Ok(()) => Ok(()),
138            Err(e) => {
139                self.set_error(e.clone());
140                Err(e)
141            }
142        }
143    }
144
145    /// Parses an XML document from a byte slice in place.
146    ///
147    /// Rejects non-UTF-8 inputs. Any existing DOM structure is cleared.
148    pub fn parse_bytes_mut(&mut self, bytes: &[u8]) -> Result<()> {
149        let s = str::from_utf8(bytes).map_err(|e| {
150            let err = XmlError::Parse {
151                kind: crate::error::ParseErrorKind::General,
152                line: 1,
153                message: Some(format!("Invalid UTF-8 sequence: {e}")),
154            };
155            self.set_error(err.clone());
156            err
157        })?;
158        self.parse_str(s)
159    }
160
161    /// Loads and parses an XML file from the given path in place.
162    ///
163    /// Any existing DOM structure is cleared.
164    #[cfg(feature = "std")]
165    pub fn load_file_mut(&mut self, path: impl AsRef<std::path::Path>) -> Result<()> {
166        let bytes = std::fs::read(path)?;
167        self.parse_bytes_mut(&bytes)
168    }
169
170    /// Parses an XML document from a string slice, returning the new Document.
171    pub fn parse(xml: &str) -> Result<Self> {
172        let mut doc = Self::new();
173        doc.parse_str(xml)?;
174        Ok(doc)
175    }
176
177    /// Parses an XML document from a byte slice, returning the new Document.
178    ///
179    /// Rejects non-UTF-8 inputs.
180    pub fn parse_bytes(bytes: &[u8]) -> Result<Self> {
181        let mut doc = Self::new();
182        doc.parse_bytes_mut(bytes)?;
183        Ok(doc)
184    }
185
186    /// Loads and parses an XML file from the given path, returning the new Document.
187    #[cfg(feature = "std")]
188    pub fn load_file(path: impl AsRef<std::path::Path>) -> Result<Self> {
189        let mut doc = Self::new();
190        doc.load_file_mut(path)?;
191        Ok(doc)
192    }
193
194    // --- Factory Methods ---
195
196    /// Creates a new detached Element node in the document's arena.
197    pub fn new_element(&mut self, name: &str) -> NodeId {
198        let kind = NodeKind::Element(ElementData {
199            name: name.to_string(),
200            attributes: Vec::new(),
201        });
202        self.arena.alloc(NodeData::new(kind, 1))
203    }
204
205    /// Creates a new detached Text node in the document's arena.
206    pub fn new_text(&mut self, text: &str) -> NodeId {
207        let kind = NodeKind::Text(TextData {
208            content: text.to_string(),
209            is_cdata: false,
210        });
211        self.arena.alloc(NodeData::new(kind, 1))
212    }
213
214    /// Creates a new detached CDATA Text node in the document's arena.
215    pub fn new_cdata(&mut self, text: &str) -> NodeId {
216        let kind = NodeKind::Text(TextData {
217            content: text.to_string(),
218            is_cdata: true,
219        });
220        self.arena.alloc(NodeData::new(kind, 1))
221    }
222
223    /// Creates a new detached Comment node in the document's arena.
224    pub fn new_comment(&mut self, text: &str) -> NodeId {
225        let kind = NodeKind::Comment(text.to_string());
226        self.arena.alloc(NodeData::new(kind, 1))
227    }
228
229    /// Creates a new detached Declaration node in the document's arena.
230    pub fn new_declaration(&mut self, decl: &str) -> NodeId {
231        let kind = NodeKind::Declaration(ElementData {
232            name: decl.to_string(),
233            attributes: Vec::new(),
234        });
235        self.arena.alloc(NodeData::new(kind, 1))
236    }
237
238    /// Creates a new detached Unknown node in the document's arena.
239    pub fn new_unknown(&mut self, text: &str) -> NodeId {
240        let kind = NodeKind::Unknown(text.to_string());
241        self.arena.alloc(NodeData::new(kind, 1))
242    }
243
244    // --- Navigation APIs ---
245
246    /// Returns the parent of the specified node, if it exists.
247    #[must_use]
248    pub fn parent(&self, node: NodeId) -> Option<NodeId> {
249        self.arena.get(node).and_then(|d| d.parent)
250    }
251
252    /// Returns the first child of the specified node, if it exists.
253    #[must_use]
254    pub fn first_child(&self, node: NodeId) -> Option<NodeId> {
255        self.arena.get(node).and_then(|d| d.first_child)
256    }
257
258    /// Returns the last child of the specified node, if it exists.
259    #[must_use]
260    pub fn last_child(&self, node: NodeId) -> Option<NodeId> {
261        self.arena.get(node).and_then(|d| d.last_child)
262    }
263
264    /// Returns the previous sibling of the specified node, if it exists.
265    #[must_use]
266    pub fn prev_sibling(&self, node: NodeId) -> Option<NodeId> {
267        self.arena.get(node).and_then(|d| d.prev_sibling)
268    }
269
270    /// Returns the next sibling of the specified node, if it exists.
271    #[must_use]
272    pub fn next_sibling(&self, node: NodeId) -> Option<NodeId> {
273        self.arena.get(node).and_then(|d| d.next_sibling)
274    }
275
276    /// Returns the first child Element of the specified node, optionally matching a tag name.
277    #[must_use]
278    pub fn first_child_element(&self, node: NodeId, name: Option<&str>) -> Option<NodeId> {
279        let mut current = self.first_child(node);
280        while let Some(curr) = current {
281            if let Some(data) = self.arena.get(curr) {
282                if let NodeKind::Element(el_data) = &data.kind {
283                    if name.is_none_or(|n| el_data.name == n) {
284                        return Some(curr);
285                    }
286                }
287            }
288            current = self.next_sibling(curr);
289        }
290        None
291    }
292
293    /// Returns the last child Element of the specified node, optionally matching a tag name.
294    #[must_use]
295    pub fn last_child_element(&self, node: NodeId, name: Option<&str>) -> Option<NodeId> {
296        let mut current = self.last_child(node);
297        while let Some(curr) = current {
298            if let Some(data) = self.arena.get(curr) {
299                if let NodeKind::Element(el_data) = &data.kind {
300                    if name.is_none_or(|n| el_data.name == n) {
301                        return Some(curr);
302                    }
303                }
304            }
305            current = self.prev_sibling(curr);
306        }
307        None
308    }
309
310    /// Returns the next sibling Element of the specified node, optionally matching a tag name.
311    #[must_use]
312    pub fn next_sibling_element(&self, node: NodeId, name: Option<&str>) -> Option<NodeId> {
313        let mut current = self.next_sibling(node);
314        while let Some(curr) = current {
315            if let Some(data) = self.arena.get(curr) {
316                if let NodeKind::Element(el_data) = &data.kind {
317                    if name.is_none_or(|n| el_data.name == n) {
318                        return Some(curr);
319                    }
320                }
321            }
322            current = self.next_sibling(curr);
323        }
324        None
325    }
326
327    /// Returns the previous sibling Element of the specified node, optionally matching a tag name.
328    #[must_use]
329    pub fn prev_sibling_element(&self, node: NodeId, name: Option<&str>) -> Option<NodeId> {
330        let mut current = self.prev_sibling(node);
331        while let Some(curr) = current {
332            if let Some(data) = self.arena.get(curr) {
333                if let NodeKind::Element(el_data) = &data.kind {
334                    if name.is_none_or(|n| el_data.name == n) {
335                        return Some(curr);
336                    }
337                }
338            }
339            current = self.prev_sibling(curr);
340        }
341        None
342    }
343
344    /// Returns the root Element of the document (the first element child of the root document node).
345    #[must_use]
346    pub fn root_element(&self) -> Option<NodeId> {
347        self.first_child_element(self.root, None)
348    }
349
350    // --- Invariant Checks & Tree Linkage Helpers ---
351
352    /// Returns `true` if `ancestor` is an ancestor of `descendant` (or the same node).
353    fn is_ancestor(&self, ancestor: NodeId, mut descendant: NodeId) -> bool {
354        if ancestor == descendant {
355            return true;
356        }
357        while let Some(parent) = self.parent(descendant) {
358            if parent == ancestor {
359                return true;
360            }
361            descendant = parent;
362        }
363        false
364    }
365
366    /// Unlinks a node from its parent and siblings.
367    fn unlink(&mut self, node: NodeId) -> Result<()> {
368        let data = self.arena.get(node).ok_or(XmlError::InvalidNodeId)?.clone();
369        if let Some(parent) = data.parent {
370            let p_data = self.arena.get_mut(parent).ok_or(XmlError::InvalidNodeId)?;
371            if p_data.first_child == Some(node) {
372                p_data.first_child = data.next_sibling;
373            }
374            if p_data.last_child == Some(node) {
375                p_data.last_child = data.prev_sibling;
376            }
377        }
378        if let Some(prev) = data.prev_sibling {
379            if let Some(prev_node) = self.arena.get_mut(prev) {
380                prev_node.next_sibling = data.next_sibling;
381            }
382        }
383        if let Some(next) = data.next_sibling {
384            if let Some(next_node) = self.arena.get_mut(next) {
385                next_node.prev_sibling = data.prev_sibling;
386            }
387        }
388
389        let node_mut = self.arena.get_mut(node).ok_or(XmlError::InvalidNodeId)?;
390        node_mut.parent = None;
391        node_mut.prev_sibling = None;
392        node_mut.next_sibling = None;
393        Ok(())
394    }
395
396    // --- Tree Mutation APIs ---
397
398    /// Inserts `child` as the last child of `parent`.
399    pub fn insert_end_child(&mut self, parent: NodeId, child: NodeId) -> Result<NodeId> {
400        if !self.arena.contains(parent) || !self.arena.contains(child) {
401            return Err(XmlError::InvalidNodeId);
402        }
403        if self.is_ancestor(child, parent) {
404            return Err(XmlError::InvalidNodeId);
405        }
406
407        self.unlink(child)?;
408
409        let parent_data = self.arena.get(parent).ok_or(XmlError::InvalidNodeId)?;
410        let old_last = parent_data.last_child;
411
412        if let Some(last) = old_last {
413            let last_node = self.arena.get_mut(last).ok_or(XmlError::InvalidNodeId)?;
414            last_node.next_sibling = Some(child);
415        }
416
417        let child_node = self.arena.get_mut(child).ok_or(XmlError::InvalidNodeId)?;
418        child_node.parent = Some(parent);
419        child_node.prev_sibling = old_last;
420        child_node.next_sibling = None;
421
422        let parent_node = self.arena.get_mut(parent).ok_or(XmlError::InvalidNodeId)?;
423        if parent_node.first_child.is_none() {
424            parent_node.first_child = Some(child);
425        }
426        parent_node.last_child = Some(child);
427
428        Ok(child)
429    }
430
431    /// Inserts `child` as the first child of `parent`.
432    pub fn insert_first_child(&mut self, parent: NodeId, child: NodeId) -> Result<NodeId> {
433        if !self.arena.contains(parent) || !self.arena.contains(child) {
434            return Err(XmlError::InvalidNodeId);
435        }
436        if self.is_ancestor(child, parent) {
437            return Err(XmlError::InvalidNodeId);
438        }
439
440        self.unlink(child)?;
441
442        let parent_data = self.arena.get(parent).ok_or(XmlError::InvalidNodeId)?;
443        let old_first = parent_data.first_child;
444
445        if let Some(first) = old_first {
446            let first_node = self.arena.get_mut(first).ok_or(XmlError::InvalidNodeId)?;
447            first_node.prev_sibling = Some(child);
448        }
449
450        let child_node = self.arena.get_mut(child).ok_or(XmlError::InvalidNodeId)?;
451        child_node.parent = Some(parent);
452        child_node.prev_sibling = None;
453        child_node.next_sibling = old_first;
454
455        let parent_node = self.arena.get_mut(parent).ok_or(XmlError::InvalidNodeId)?;
456        if parent_node.last_child.is_none() {
457            parent_node.last_child = Some(child);
458        }
459        parent_node.first_child = Some(child);
460
461        Ok(child)
462    }
463
464    /// Inserts `child` immediately after `after`.
465    pub fn insert_after_child(&mut self, after: NodeId, child: NodeId) -> Result<NodeId> {
466        if !self.arena.contains(after) || !self.arena.contains(child) {
467            return Err(XmlError::InvalidNodeId);
468        }
469        let parent = self.parent(after).ok_or(XmlError::InvalidNodeId)?;
470        if self.is_ancestor(child, parent) {
471            return Err(XmlError::InvalidNodeId);
472        }
473
474        self.unlink(child)?;
475
476        let after_data = self.arena.get(after).ok_or(XmlError::InvalidNodeId)?;
477        let old_next = after_data.next_sibling;
478
479        if let Some(next) = old_next {
480            let next_node = self.arena.get_mut(next).ok_or(XmlError::InvalidNodeId)?;
481            next_node.prev_sibling = Some(child);
482        }
483
484        let child_node = self.arena.get_mut(child).ok_or(XmlError::InvalidNodeId)?;
485        child_node.parent = Some(parent);
486        child_node.prev_sibling = Some(after);
487        child_node.next_sibling = old_next;
488
489        let after_node = self.arena.get_mut(after).ok_or(XmlError::InvalidNodeId)?;
490        after_node.next_sibling = Some(child);
491
492        let parent_node = self.arena.get_mut(parent).ok_or(XmlError::InvalidNodeId)?;
493        if parent_node.last_child == Some(after) {
494            parent_node.last_child = Some(child);
495        }
496
497        Ok(child)
498    }
499
500    /// Helper for recursive deallocation of a node and all of its descendants.
501    fn delete_recursive(&mut self, node: NodeId) {
502        let mut next_child = self.first_child(node);
503        while let Some(child) = next_child {
504            let sibling = self.next_sibling(child);
505            self.delete_recursive(child);
506            next_child = sibling;
507        }
508        self.arena.dealloc(node);
509    }
510
511    /// Removes `child` from `parent` and deallocates it recursively.
512    pub fn delete_child(&mut self, parent: NodeId, child: NodeId) -> Result<()> {
513        if !self.arena.contains(parent) || !self.arena.contains(child) {
514            return Err(XmlError::InvalidNodeId);
515        }
516        if self.parent(child) != Some(parent) {
517            return Err(XmlError::InvalidNodeId);
518        }
519
520        self.unlink(child)?;
521        self.delete_recursive(child);
522        Ok(())
523    }
524
525    /// Removes and deallocates all children of `parent`.
526    pub fn delete_children(&mut self, parent: NodeId) -> Result<()> {
527        if !self.arena.contains(parent) {
528            return Err(XmlError::InvalidNodeId);
529        }
530
531        let mut next_child = self.first_child(parent);
532        while let Some(child) = next_child {
533            let sibling = self.next_sibling(child);
534            self.unlink(child)?;
535            self.delete_recursive(child);
536            next_child = sibling;
537        }
538
539        let parent_node = self.arena.get_mut(parent).ok_or(XmlError::InvalidNodeId)?;
540        parent_node.first_child = None;
541        parent_node.last_child = None;
542        Ok(())
543    }
544
545    /// Unlinks `node` from its parent and recursively deallocates it.
546    pub fn delete_node(&mut self, node: NodeId) -> Result<()> {
547        if !self.arena.contains(node) {
548            return Err(XmlError::InvalidNodeId);
549        }
550        if node == self.root {
551            return Err(XmlError::InvalidNodeId);
552        }
553
554        self.unlink(node)?;
555        self.delete_recursive(node);
556        Ok(())
557    }
558
559    // --- Clone Operations ---
560
561    /// Creates a shallow clone of the node (clones type & data only; no children, detached).
562    pub fn shallow_clone(&mut self, node: NodeId) -> Result<NodeId> {
563        let data = self.arena.get(node).ok_or(XmlError::InvalidNodeId)?.clone();
564        let cloned_kind = match &data.kind {
565            NodeKind::Document => NodeKind::Document,
566            NodeKind::Element(el) => NodeKind::Element(el.clone()),
567            NodeKind::Text(txt) => NodeKind::Text(txt.clone()),
568            NodeKind::Comment(c) => NodeKind::Comment(c.clone()),
569            NodeKind::Declaration(d) => NodeKind::Declaration(d.clone()),
570            NodeKind::Unknown(u) => NodeKind::Unknown(u.clone()),
571        };
572        let cloned_data = NodeData::new(cloned_kind, data.line_num);
573        let cloned_id = self.arena.alloc(cloned_data);
574        Ok(cloned_id)
575    }
576
577    /// Recursively clones a node and all of its descendants.
578    pub fn deep_clone(&mut self, node: NodeId) -> Result<NodeId> {
579        let cloned_id = self.shallow_clone(node)?;
580        let mut next_child = self.first_child(node);
581        while let Some(child) = next_child {
582            let cloned_child = self.deep_clone(child)?;
583            self.insert_end_child(cloned_id, cloned_child)?;
584            next_child = self.next_sibling(child);
585        }
586        Ok(cloned_id)
587    }
588
589    // --- Attribute Manipulation ---
590
591    /// Returns the string value of the attribute on element `el` if it exists.
592    #[must_use]
593    pub fn attribute(&self, el: NodeId, name: &str) -> Option<&str> {
594        let data = self.arena.get(el)?;
595        match &data.kind {
596            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => el_data
597                .attributes
598                .iter()
599                .find(|attr| attr.name == name)
600                .map(|attr| attr.value.as_str()),
601            _ => None,
602        }
603    }
604
605    /// Sets the value of an attribute on element `el` (inserts or updates).
606    pub fn set_attribute(&mut self, el: NodeId, name: &str, value: &str) -> Result<()> {
607        let data = self.arena.get_mut(el).ok_or(XmlError::InvalidNodeId)?;
608        match &mut data.kind {
609            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
610                if let Some(attr) = el_data.attributes.iter_mut().find(|attr| attr.name == name) {
611                    attr.value = value.to_string();
612                } else {
613                    el_data.attributes.push(Attribute {
614                        name: name.to_string(),
615                        value: value.to_string(),
616                    });
617                }
618                Ok(())
619            }
620            _ => Err(XmlError::InvalidNodeId),
621        }
622    }
623
624    /// Removes an attribute from element `el`.
625    pub fn delete_attribute(&mut self, el: NodeId, name: &str) -> Result<()> {
626        let data = self.arena.get_mut(el).ok_or(XmlError::InvalidNodeId)?;
627        match &mut data.kind {
628            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
629                if let Some(pos) = el_data.attributes.iter().position(|attr| attr.name == name) {
630                    el_data.attributes.remove(pos);
631                    Ok(())
632                } else {
633                    Err(XmlError::NoAttribute)
634                }
635            }
636            _ => Err(XmlError::InvalidNodeId),
637        }
638    }
639
640    /// Returns a reference to the first Attribute on element `el`.
641    #[must_use]
642    pub fn first_attribute(&self, el: NodeId) -> Option<&Attribute> {
643        let data = self.arena.get(el)?;
644        match &data.kind {
645            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
646                el_data.attributes.first()
647            }
648            _ => None,
649        }
650    }
651
652    /// Returns the number of attributes on element `el`.
653    #[must_use]
654    pub fn attribute_count(&self, el: NodeId) -> usize {
655        let Some(data) = self.arena.get(el) else {
656            return 0;
657        };
658        match &data.kind {
659            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => el_data.attributes.len(),
660            _ => 0,
661        }
662    }
663
664    /// Finds a reference to the Attribute with the specified name.
665    #[must_use]
666    pub fn find_attribute(&self, el: NodeId, name: &str) -> Option<&Attribute> {
667        let data = self.arena.get(el)?;
668        match &data.kind {
669            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
670                el_data.attributes.iter().find(|attr| attr.name == name)
671            }
672            _ => None,
673        }
674    }
675
676    /// Returns an iterator over all attributes of element `el`.
677    pub fn iterate_attributes(&self, el: NodeId) -> impl Iterator<Item = &Attribute> {
678        let attrs = match self.arena.get(el) {
679            Some(data) => match &data.kind {
680                NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
681                    &el_data.attributes[..]
682                }
683                _ => &[],
684            },
685            None => &[],
686        };
687        attrs.iter()
688    }
689
690    // --- Iterator & Ref Convenience APIs ---
691
692    /// Returns an iterator over the direct children of `parent`.
693    pub fn children(&self, parent: NodeId) -> crate::iter::Children<'_> {
694        crate::iter::Children::new(self, parent)
695    }
696
697    /// Returns an iterator over the direct child elements of `parent`,
698    /// optionally filtered by tag name.
699    pub fn child_elements(
700        &self,
701        parent: NodeId,
702        name: Option<&str>,
703    ) -> crate::iter::ChildElements<'_> {
704        crate::iter::ChildElements::new(self, parent, name)
705    }
706
707    /// Returns an iterator over the following siblings of `node`.
708    pub fn siblings(&self, node: NodeId) -> crate::iter::Siblings<'_> {
709        crate::iter::Siblings::new(self, node)
710    }
711
712    /// Returns a depth-first pre-order iterator over all descendants of `root`.
713    pub fn descendants(&self, root: NodeId) -> crate::iter::Descendants<'_> {
714        crate::iter::Descendants::new(self, root)
715    }
716
717    /// Returns an iterator over the attributes of element `el`.
718    pub fn attributes(&self, el: NodeId) -> crate::iter::Attributes<'_> {
719        let Some(data) = self.arena.get(el) else {
720            return crate::iter::Attributes::empty();
721        };
722        match &data.kind {
723            NodeKind::Element(el_data) | NodeKind::Declaration(el_data) => {
724                crate::iter::Attributes::new(&el_data.attributes)
725            }
726            _ => crate::iter::Attributes::empty(),
727        }
728    }
729
730    /// Creates an immutable navigation [`Handle`](crate::handle::Handle) for the given node.
731    pub fn handle(&self, node: NodeId) -> crate::handle::Handle<'_> {
732        crate::handle::Handle::new(self, node)
733    }
734
735    /// Creates a mutable navigation [`HandleMut`](crate::handle::HandleMut) for the given node.
736    pub fn handle_mut(&mut self, node: NodeId) -> crate::handle::HandleMut<'_> {
737        crate::handle::HandleMut::new(self, node)
738    }
739
740    /// Returns a [`NodeRef`](crate::refs::NodeRef) for the given node, if it exists.
741    pub fn node_ref(&self, id: NodeId) -> Option<crate::refs::NodeRef<'_>> {
742        if self.arena.contains(id) {
743            Some(crate::refs::NodeRef::new(self, id))
744        } else {
745            None
746        }
747    }
748
749    /// Returns an [`ElementRef`](crate::refs::ElementRef) for the given node,
750    /// if it exists and is an Element.
751    pub fn element_ref(&self, id: NodeId) -> Option<crate::refs::ElementRef<'_>> {
752        let data = self.arena.get(id)?;
753        match &data.kind {
754            NodeKind::Element(_) => Some(crate::refs::ElementRef::new(self, id)),
755            _ => None,
756        }
757    }
758
759    // --- Visitor / Traversal APIs ---
760
761    /// Walk the DOM tree starting at the document root, driving the visitor.
762    pub fn accept(&self, visitor: &mut dyn crate::visitor::XmlVisitor) -> bool {
763        self.accept_node(self.root, visitor)
764    }
765
766    /// Walk the DOM tree starting at the specified node, driving the visitor.
767    pub fn accept_node(&self, node: NodeId, visitor: &mut dyn crate::visitor::XmlVisitor) -> bool {
768        if !self.arena.contains(node) {
769            return false;
770        }
771
772        let Some(data) = self.arena.get(node) else {
773            return false;
774        };
775
776        match &data.kind {
777            NodeKind::Document => {
778                if !visitor.visit_enter_document(self) {
779                    return false;
780                }
781                let mut current = self.first_child(node);
782                while let Some(child) = current {
783                    if !self.accept_node(child, visitor) {
784                        return false;
785                    }
786                    current = self.next_sibling(child);
787                }
788                if !visitor.visit_exit_document(self) {
789                    return false;
790                }
791            }
792            NodeKind::Element(_) => {
793                if !visitor.visit_enter_element(self, node) {
794                    return false;
795                }
796                let mut current = self.first_child(node);
797                while let Some(child) = current {
798                    if !self.accept_node(child, visitor) {
799                        return false;
800                    }
801                    current = self.next_sibling(child);
802                }
803                if !visitor.visit_exit_element(self, node) {
804                    return false;
805                }
806            }
807            NodeKind::Text(_) => {
808                if !visitor.visit_text(self, node) {
809                    return false;
810                }
811            }
812            NodeKind::Comment(_) => {
813                if !visitor.visit_comment(self, node) {
814                    return false;
815                }
816            }
817            NodeKind::Declaration(_) => {
818                if !visitor.visit_declaration(self, node) {
819                    return false;
820                }
821            }
822            NodeKind::Unknown(_) => {
823                if !visitor.visit_unknown(self, node) {
824                    return false;
825                }
826            }
827        }
828        true
829    }
830
831    // --- Serialization APIs ---
832
833    /// Pretty-prints the entire document to a String.
834    #[must_use]
835    #[allow(clippy::inherent_to_string_shadow_display)]
836    pub fn to_string(&self) -> String {
837        let mut printer = crate::printer::XmlPrinter::new();
838        self.accept(&mut printer);
839        printer.into_string()
840    }
841
842    /// Compact-prints the entire document to a String.
843    #[must_use]
844    pub fn to_string_compact(&self) -> String {
845        let mut printer = crate::printer::XmlPrinter::new_compact();
846        self.accept(&mut printer);
847        printer.into_string()
848    }
849
850    /// Saves the pretty-printed document to the given file path.
851    #[cfg(feature = "std")]
852    pub fn save_file(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
853        let file = std::fs::File::create(path)?;
854        self.save_writer(file)
855    }
856
857    /// Saves the compact-printed document to the given file path.
858    #[cfg(feature = "std")]
859    pub fn save_file_compact(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
860        let file = std::fs::File::create(path)?;
861        self.save_writer_compact(file)
862    }
863
864    /// Pretty-prints the document to the given `std::io::Write` sink.
865    #[cfg(feature = "std")]
866    pub fn save_writer(&self, mut writer: impl std::io::Write) -> Result<()> {
867        let s = self.to_string();
868        writer.write_all(s.as_bytes())?;
869        Ok(())
870    }
871
872    /// Compact-prints the document to the given `std::io::Write` sink.
873    #[cfg(feature = "std")]
874    pub fn save_writer_compact(&self, mut writer: impl std::io::Write) -> Result<()> {
875        let s = self.to_string_compact();
876        writer.write_all(s.as_bytes())?;
877        Ok(())
878    }
879}
880
881impl Default for Document {
882    fn default() -> Self {
883        Self::new()
884    }
885}
886
887impl fmt::Display for Document {
888    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889        write!(f, "{}", self.to_string())
890    }
891}