Skip to main content

rusty_xml_tree/
lib.rs

1//! Arena DOM matching libxml2 `tree.h` ownership: the document owns every node.
2//! Handles are indices, not parent+child `&mut` pairs.
3
4#![forbid(unsafe_code)]
5
6use std::collections::HashMap;
7
8/// libxml2 `xmlElementType` discriminants.
9#[derive(Clone, Copy, PartialEq, Eq, Debug)]
10#[repr(u32)]
11pub enum NodeKind {
12    Element = 1,
13    Attribute = 2,
14    Text = 3,
15    CData = 4,
16    EntityRef = 5,
17    Entity = 6,
18    Pi = 7,
19    Comment = 8,
20    Document = 9,
21    DocumentType = 10,
22    DocumentFrag = 11,
23    Notation = 12,
24    HtmlDocument = 13,
25    Dtd = 14,
26    ElementDecl = 15,
27    AttributeDecl = 16,
28    EntityDecl = 17,
29    Namespace = 18,
30    XIncludeStart = 19,
31    XIncludeEnd = 20,
32}
33
34/// Parsed DTD attached to a document (`xmlDtd`).
35#[derive(Clone, Debug, Default)]
36pub struct XmlDtd {
37    pub name: Option<String>,
38    pub public_id: Option<String>,
39    pub system_id: Option<String>,
40    pub int_subset: Option<String>,
41    /// General entity name → replacement text.
42    pub entities: HashMap<String, String>,
43    /// Parameter entity name → replacement.
44    pub parameter_entities: HashMap<String, String>,
45    /// Names of entities declared with an NDATA annotation. An attribute of
46    /// type ENTITY must name one of these, which needs them kept apart from
47    /// parsed entities rather than lumped in with them.
48    pub unparsed_entities: std::collections::HashSet<String>,
49    /// Element name → content model.
50    pub elements: HashMap<String, ElementDecl>,
51    /// Element types declared more than once. A map cannot represent that, and
52    /// "Unique Element Type Declaration" is a validity constraint, so it has to
53    /// be recorded as the declarations go by and reported at validation time
54    /// rather than at parse time.
55    pub duplicate_elements: Vec<String>,
56    /// (element, attribute) → declaration.
57    pub attributes: HashMap<(String, String), AttrDecl>,
58}
59
60#[derive(Clone, Debug)]
61pub enum ElementDecl {
62    Empty,
63    Any,
64    Mixed(Vec<String>),
65    Children(String),
66}
67
68#[derive(Clone, Debug)]
69pub struct AttrDecl {
70    pub att_type: String,
71    pub default: AttrDefault,
72    pub default_value: Option<String>,
73    pub enumerated: Vec<String>,
74}
75
76#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77pub enum AttrDefault {
78    Required,
79    Implied,
80    Fixed,
81    Value,
82}
83
84/// Stable handle into an [`XmlDoc`] arena. Valid for the lifetime of the doc.
85#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
86pub struct NodeId(pub u32);
87
88impl NodeId {
89    /// Document node is always slot 0.
90    pub const DOCUMENT: NodeId = NodeId(0);
91
92    pub fn index(self) -> usize {
93        self.0 as usize
94    }
95}
96
97
98
99#[derive(Clone, Debug)]
100pub struct Node {
101    pub kind: NodeKind,
102    pub name: String,
103    pub prefix: Option<String>,
104    pub ns_uri: Option<String>,
105    pub content: String,
106    pub parent: Option<NodeId>,
107    pub first_child: Option<NodeId>,
108    pub last_child: Option<NodeId>,
109    pub prev_sibling: Option<NodeId>,
110    pub next_sibling: Option<NodeId>,
111    pub first_attr: Option<NodeId>,
112    pub last_attr: Option<NodeId>,
113    /// Namespace declarations on this element (`xmlns` / `xmlns:prefix`), in source order.
114    pub ns_defs: Vec<(Option<String>, String)>,
115}
116
117impl Node {
118    fn new(kind: NodeKind, name: String) -> Self {
119        Self {
120            kind,
121            name,
122            prefix: None,
123            ns_uri: None,
124            content: String::new(),
125            parent: None,
126            first_child: None,
127            last_child: None,
128            prev_sibling: None,
129            next_sibling: None,
130            first_attr: None,
131            last_attr: None,
132            ns_defs: Vec::new(),
133        }
134    }
135}
136
137/// libxml2 `xmlDoc`.
138#[derive(Clone, Debug)]
139pub struct XmlDoc {
140    nodes: Vec<Node>,
141    /// XML version string; default `"1.0"`.
142    pub version: String,
143    /// Encoding name from the XML declaration, if any.
144    pub encoding: Option<String>,
145    /// `Some(true/false)` from `standalone`, `None` if omitted.
146    pub standalone: Option<bool>,
147    /// First element child of the document (cached; also discoverable by walk).
148    root: Option<NodeId>,
149    /// Internal / attached DTD, if any.
150    pub dtd: Option<XmlDtd>,
151}
152
153impl Default for XmlDoc {
154    fn default() -> Self {
155        Self::xml_new_doc(Some("1.0"))
156    }
157}
158
159impl XmlDoc {
160    /// `xmlNewDoc`.
161    #[doc(alias = "xmlNewDoc")]
162    pub fn xml_new_doc(version: Option<&str>) -> Self {
163        Self::with_node_capacity(version, 1)
164    }
165
166    /// Build a document whose node arena is sized up front. Starting a parse
167    /// used to allocate the arena, push into it, then reallocate on reserve --
168    /// three trips for what one sized allocation does. The document node's
169    /// name is implied by its kind, so it stores no String either.
170    pub fn with_node_capacity(version: Option<&str>, cap: usize) -> Self {
171        const MAX_ARENA_BYTES: usize = 32 << 20;
172        let ceiling = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
173        // A floor of 4 keeps a small document from reallocating its way up
174        // from a single slot, which is what Vec::new()+push used to give it.
175        let mut nodes = Vec::with_capacity(cap.clamp(4, ceiling));
176        nodes.push(Node::new(NodeKind::Document, String::new()));
177        Self {
178            nodes,
179            version: version.unwrap_or("1.0").to_string(),
180            encoding: None,
181            standalone: None,
182            root: None,
183            dtd: None,
184        }
185    }
186
187    /// Pre-size the node arena. XML runs about one node per 10-15 input bytes,
188    /// so a parser that knows the document length can skip most of the arena's
189    /// doubling-and-copy. Capped so a huge document cannot reserve wildly.
190    pub fn reserve_nodes(&mut self, n: usize) {
191        // Measured node density is ~1 per 10-12 input bytes. The previous cap
192        // of 65_536 was below a 700 KB document's node count, so the arena
193        // still doubled-and-copied its way up -- about 22 MB of memcpy on a
194        // 627 KB file. Shrinking Node itself would need an API break for a
195        // sub-1% effect; reserving correctly removes the same traffic for free.
196        // Cap by memory, not node count: 1<<20 nodes is ~190 MB of arena, which
197        // a large document would commit up front before parsing a byte.
198        const MAX_ARENA_BYTES: usize = 32 << 20;
199        let cap = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
200        self.nodes.reserve(n.min(cap));
201    }
202
203    pub fn node(&self, id: NodeId) -> &Node {
204        &self.nodes[id.index()]
205    }
206
207    pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
208        &mut self.nodes[id.index()]
209    }
210
211    pub fn kind(&self, id: NodeId) -> NodeKind {
212        self.node(id).kind
213    }
214
215    pub fn name(&self, id: NodeId) -> &str {
216        let n = self.node(id);
217        if n.name.is_empty() {
218            // Nodes whose name is fixed by their kind store no String at all;
219            // allocating "#text" once per text node was a measurable share of
220            // every parse. The canonical name is derived here instead.
221            return match n.kind {
222                NodeKind::Text => "#text",
223                NodeKind::CData => "#cdata-section",
224                NodeKind::Comment => "#comment",
225                NodeKind::Document => "#document",
226                _ => "",
227            };
228        }
229        &n.name
230    }
231
232    pub fn prefix(&self, id: NodeId) -> Option<&str> {
233        self.node(id).prefix.as_deref()
234    }
235
236    pub fn ns_uri(&self, id: NodeId) -> Option<&str> {
237        self.node(id).ns_uri.as_deref()
238    }
239
240    pub fn content(&self, id: NodeId) -> &str {
241        &self.node(id).content
242    }
243
244    pub fn parent(&self, id: NodeId) -> Option<NodeId> {
245        self.node(id).parent
246    }
247
248    pub fn first_child(&self, id: NodeId) -> Option<NodeId> {
249        self.node(id).first_child
250    }
251
252    pub fn last_child(&self, id: NodeId) -> Option<NodeId> {
253        self.node(id).last_child
254    }
255
256    pub fn next_sibling(&self, id: NodeId) -> Option<NodeId> {
257        self.node(id).next_sibling
258    }
259
260    pub fn prev_sibling(&self, id: NodeId) -> Option<NodeId> {
261        self.node(id).prev_sibling
262    }
263
264    pub fn first_attr(&self, id: NodeId) -> Option<NodeId> {
265        self.node(id).first_attr
266    }
267
268    pub fn ns_defs(&self, id: NodeId) -> &[(Option<String>, String)] {
269        &self.node(id).ns_defs
270    }
271
272    /// Allocate a node whose name is implied by its kind, storing no String.
273    /// [`XmlDoc::name`] reports the canonical name for these.
274    pub fn alloc_unnamed(&mut self, kind: NodeKind) -> NodeId {
275        let id = NodeId(self.nodes.len() as u32);
276        self.nodes.push(Node::new(kind, String::new()));
277        id
278    }
279
280    pub fn alloc(&mut self, kind: NodeKind, name: impl Into<String>) -> NodeId {
281        let id = NodeId(self.nodes.len() as u32);
282        self.nodes.push(Node::new(kind, name.into()));
283        id
284    }
285
286    /// `xmlDocGetRootElement`.
287    #[doc(alias = "xmlDocGetRootElement")]
288    pub fn xml_doc_get_root_element(&self) -> Option<NodeId> {
289        if let Some(r) = self.root {
290            return Some(r);
291        }
292        let mut c = self.first_child(NodeId::DOCUMENT);
293        while let Some(id) = c {
294            if self.kind(id) == NodeKind::Element {
295                return Some(id);
296            }
297            c = self.next_sibling(id);
298        }
299        None
300    }
301
302    /// `xmlDocSetRootElement`. Returns the previous root, if any.
303    #[doc(alias = "xmlDocSetRootElement")]
304    pub fn xml_doc_set_root_element(&mut self, elem: NodeId) -> Option<NodeId> {
305        let prev = self.xml_doc_get_root_element();
306        if let Some(p) = prev {
307            self.xml_unlink_node(p);
308        }
309        self.xml_add_child(NodeId::DOCUMENT, elem);
310        self.root = Some(elem);
311        prev
312    }
313
314    /// `xmlNewNode`.
315    #[doc(alias = "xmlNewNode")]
316    pub fn xml_new_node(&mut self, ns_uri: Option<&str>, name: &str) -> NodeId {
317        let id = self.alloc(NodeKind::Element, name);
318        self.node_mut(id).ns_uri = ns_uri.map(str::to_string);
319        id
320    }
321
322    /// `xmlNewDocNode`.
323    #[doc(alias = "xmlNewDocNode")]
324    pub fn xml_new_doc_node(
325        &mut self,
326        ns_uri: Option<&str>,
327        name: &str,
328        content: Option<&str>,
329    ) -> NodeId {
330        let id = self.xml_new_node(ns_uri, name);
331        if let Some(c) = content {
332            if !c.is_empty() {
333                let t = self.alloc(NodeKind::Text, "#text");
334                self.node_mut(t).content = c.to_string();
335                self.xml_add_child(id, t);
336            }
337        }
338        id
339    }
340
341    /// `xmlNewChild`.
342    #[doc(alias = "xmlNewChild")]
343    pub fn xml_new_child(
344        &mut self,
345        parent: NodeId,
346        ns_uri: Option<&str>,
347        name: &str,
348        content: Option<&str>,
349    ) -> NodeId {
350        let id = self.xml_new_doc_node(ns_uri, name, content);
351        self.xml_add_child(parent, id);
352        id
353    }
354
355    /// `xmlAddChild`.
356    #[doc(alias = "xmlAddChild")]
357    pub fn xml_add_child(&mut self, parent: NodeId, child: NodeId) {
358        if child == parent {
359            return;
360        }
361        self.xml_unlink_node(child);
362        self.node_mut(child).parent = Some(parent);
363        let last = self.node(parent).last_child;
364        if let Some(l) = last {
365            self.node_mut(l).next_sibling = Some(child);
366            self.node_mut(child).prev_sibling = Some(l);
367        } else {
368            self.node_mut(parent).first_child = Some(child);
369        }
370        self.node_mut(parent).last_child = Some(child);
371        if parent == NodeId::DOCUMENT && self.kind(child) == NodeKind::Element {
372            self.root = Some(child);
373        }
374    }
375
376    /// `xmlAddNextSibling`.
377    #[doc(alias = "xmlAddNextSibling")]
378    pub fn xml_add_next_sibling(&mut self, cur: NodeId, elem: NodeId) {
379        self.xml_unlink_node(elem);
380        let parent = self.node(cur).parent;
381        let next = self.node(cur).next_sibling;
382        self.node_mut(elem).parent = parent;
383        self.node_mut(elem).prev_sibling = Some(cur);
384        self.node_mut(elem).next_sibling = next;
385        self.node_mut(cur).next_sibling = Some(elem);
386        if let Some(n) = next {
387            self.node_mut(n).prev_sibling = Some(elem);
388        } else if let Some(p) = parent {
389            self.node_mut(p).last_child = Some(elem);
390        }
391    }
392
393    /// `xmlAddPrevSibling`.
394    #[doc(alias = "xmlAddPrevSibling")]
395    pub fn xml_add_prev_sibling(&mut self, cur: NodeId, elem: NodeId) {
396        self.xml_unlink_node(elem);
397        let parent = self.node(cur).parent;
398        let prev = self.node(cur).prev_sibling;
399        self.node_mut(elem).parent = parent;
400        self.node_mut(elem).next_sibling = Some(cur);
401        self.node_mut(elem).prev_sibling = prev;
402        self.node_mut(cur).prev_sibling = Some(elem);
403        if let Some(p) = prev {
404            self.node_mut(p).next_sibling = Some(elem);
405        } else if let Some(par) = parent {
406            self.node_mut(par).first_child = Some(elem);
407        }
408    }
409
410    /// `xmlUnlinkNode`.
411    #[doc(alias = "xmlUnlinkNode")]
412    pub fn xml_unlink_node(&mut self, id: NodeId) {
413        if id == NodeId::DOCUMENT {
414            return;
415        }
416        let parent = self.node(id).parent;
417        let prev = self.node(id).prev_sibling;
418        let next = self.node(id).next_sibling;
419        if let Some(p) = prev {
420            self.node_mut(p).next_sibling = next;
421        }
422        if let Some(n) = next {
423            self.node_mut(n).prev_sibling = prev;
424        }
425        if let Some(par) = parent {
426            if self.node(par).first_child == Some(id) {
427                self.node_mut(par).first_child = next;
428            }
429            if self.node(par).last_child == Some(id) {
430                self.node_mut(par).last_child = prev;
431            }
432        }
433        if self.root == Some(id) {
434            self.root = None;
435        }
436        self.node_mut(id).parent = None;
437        self.node_mut(id).prev_sibling = None;
438        self.node_mut(id).next_sibling = None;
439    }
440
441    /// `xmlReplaceNode`.
442    #[doc(alias = "xmlReplaceNode")]
443    pub fn xml_replace_node(&mut self, old: NodeId, new: NodeId) -> NodeId {
444        self.xml_add_next_sibling(old, new);
445        self.xml_unlink_node(old);
446        new
447    }
448
449    /// As [`XmlDoc::add_attr`], but takes ownership. The borrowing form has to
450    /// allocate a fresh String for the name, the prefix and the value, all of
451    /// which the parser already owns.
452    pub fn add_attr_owned(
453        &mut self,
454        elem: NodeId,
455        name: String,
456        prefix: Option<String>,
457        value: String,
458    ) -> NodeId {
459        let id = self.alloc(NodeKind::Attribute, name);
460        self.node_mut(id).prefix = prefix;
461        self.node_mut(id).content = value;
462        self.node_mut(id).parent = Some(elem);
463        let last = self.node(elem).last_attr;
464        if let Some(l) = last {
465            self.node_mut(l).next_sibling = Some(id);
466            self.node_mut(id).prev_sibling = Some(l);
467        } else {
468            self.node_mut(elem).first_attr = Some(id);
469        }
470        self.node_mut(elem).last_attr = Some(id);
471        id
472    }
473
474    pub fn add_attr(&mut self, elem: NodeId, name: &str, prefix: Option<&str>, value: &str) -> NodeId {
475        let id = self.alloc(NodeKind::Attribute, name);
476        self.node_mut(id).prefix = prefix.map(str::to_string);
477        self.node_mut(id).content = value.to_string();
478        self.node_mut(id).parent = Some(elem);
479        let last = self.node(elem).last_attr;
480        if let Some(l) = last {
481            self.node_mut(l).next_sibling = Some(id);
482            self.node_mut(id).prev_sibling = Some(l);
483        } else {
484            self.node_mut(elem).first_attr = Some(id);
485        }
486        self.node_mut(elem).last_attr = Some(id);
487        id
488    }
489
490    pub fn push_ns_def(&mut self, elem: NodeId, prefix: Option<String>, uri: String) {
491        self.node_mut(elem).ns_defs.push((prefix, uri));
492    }
493
494    /// `xmlSetProp`.
495    #[doc(alias = "xmlSetProp")]
496    pub fn xml_set_prop(&mut self, node: NodeId, name: &str, value: &str) -> NodeId {
497        let mut a = self.first_attr(node);
498        while let Some(id) = a {
499            if self.node(id).prefix.is_none() && self.node(id).name == name {
500                self.node_mut(id).content = value.to_string();
501                return id;
502            }
503            a = self.next_sibling(id);
504        }
505        self.add_attr(node, name, None, value)
506    }
507
508    /// `xmlGetProp`.
509    #[doc(alias = "xmlGetProp")]
510    pub fn xml_get_prop(&self, node: NodeId, name: &str) -> Option<String> {
511        let mut a = self.first_attr(node);
512        while let Some(id) = a {
513            if self.node(id).prefix.is_none() && self.node(id).name == name {
514                return Some(self.node(id).content.clone());
515            }
516            a = self.next_sibling(id);
517        }
518        None
519    }
520
521    /// `xmlHasProp`.
522    #[doc(alias = "xmlHasProp")]
523    pub fn xml_has_prop(&self, node: NodeId, name: &str) -> bool {
524        self.xml_get_prop(node, name).is_some()
525    }
526
527    /// `xmlUnsetProp`.
528    #[doc(alias = "xmlUnsetProp")]
529    pub fn xml_unset_prop(&mut self, node: NodeId, name: &str) -> bool {
530        let mut a = self.first_attr(node);
531        let mut prev: Option<NodeId> = None;
532        while let Some(id) = a {
533            let next = self.next_sibling(id);
534            if self.node(id).prefix.is_none() && self.node(id).name == name {
535                if let Some(p) = prev {
536                    self.node_mut(p).next_sibling = next;
537                } else {
538                    self.node_mut(node).first_attr = next;
539                }
540                if next.is_none() {
541                    self.node_mut(node).last_attr = prev;
542                }
543                if let Some(n) = next {
544                    self.node_mut(n).prev_sibling = prev;
545                }
546                self.node_mut(id).parent = None;
547                self.node_mut(id).prev_sibling = None;
548                self.node_mut(id).next_sibling = None;
549                return true;
550            }
551            prev = Some(id);
552            a = next;
553        }
554        false
555    }
556
557    /// `xmlNodeGetContent` — concatenate descendant text/CDATA.
558    #[doc(alias = "xmlNodeGetContent")]
559    pub fn xml_node_get_content(&self, id: NodeId) -> String {
560        match self.kind(id) {
561            NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
562                self.content(id).to_string()
563            }
564            _ => {
565                let mut out = String::new();
566                self.collect_text(id, &mut out);
567                out
568            }
569        }
570    }
571
572    fn collect_text(&self, id: NodeId, out: &mut String) {
573        let mut c = self.first_child(id);
574        while let Some(ch) = c {
575            match self.kind(ch) {
576                NodeKind::Text | NodeKind::CData => out.push_str(self.content(ch)),
577                NodeKind::Element => self.collect_text(ch, out),
578                _ => {}
579            }
580            c = self.next_sibling(ch);
581        }
582    }
583
584    /// `xmlNodeSetContent` — replace children with a single text node.
585    #[doc(alias = "xmlNodeSetContent")]
586    pub fn xml_node_set_content(&mut self, id: NodeId, content: &str) {
587        match self.kind(id) {
588            NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
589                self.node_mut(id).content = content.to_string();
590            }
591            _ => {
592                let mut c = self.first_child(id);
593                while let Some(ch) = c {
594                    let next = self.next_sibling(ch);
595                    self.xml_unlink_node(ch);
596                    c = next;
597                }
598                if !content.is_empty() {
599                    let t = self.alloc(NodeKind::Text, "#text");
600                    self.node_mut(t).content = content.to_string();
601                    self.xml_add_child(id, t);
602                }
603            }
604        }
605    }
606
607    /// `xmlIsBlankNode`.
608    #[doc(alias = "xmlIsBlankNode")]
609    pub fn xml_is_blank_node(&self, id: NodeId) -> bool {
610        match self.kind(id) {
611            NodeKind::Text | NodeKind::CData => self.content(id).chars().all(|c| {
612                c == ' ' || c == '\t' || c == '\n' || c == '\r'
613            }),
614            _ => false,
615        }
616    }
617
618    /// `xmlSearchNs` — walk ancestors for a prefix binding.
619    #[doc(alias = "xmlSearchNs")]
620    pub fn xml_search_ns(&self, node: NodeId, prefix: Option<&str>) -> Option<String> {
621        if prefix == Some("xml") {
622            return Some("http://www.w3.org/XML/1998/namespace".into());
623        }
624        if prefix == Some("xmlns") {
625            return Some("http://www.w3.org/2000/xmlns/".into());
626        }
627        let mut cur = Some(node);
628        while let Some(id) = cur {
629            for (p, uri) in self.ns_defs(id) {
630                if p.as_deref() == prefix {
631                    return Some(uri.clone());
632                }
633            }
634            cur = self.parent(id);
635        }
636        None
637    }
638
639    /// `xmlNewNs` — add a namespace declaration on an element.
640    #[doc(alias = "xmlNewNs")]
641    pub fn xml_new_ns(&mut self, node: NodeId, href: &str, prefix: Option<&str>) {
642        self.push_ns_def(node, prefix.map(str::to_string), href.to_string());
643    }
644
645    /// `xmlSetNs`.
646    #[doc(alias = "xmlSetNs")]
647    pub fn xml_set_ns(&mut self, node: NodeId, href: Option<&str>, prefix: Option<&str>) {
648        self.node_mut(node).ns_uri = href.map(str::to_string);
649        self.node_mut(node).prefix = prefix.map(str::to_string);
650    }
651
652    /// `xmlCopyDoc` — deep copy.
653    #[doc(alias = "xmlCopyDoc")]
654    pub fn xml_copy_doc(&self) -> XmlDoc {
655        self.clone()
656    }
657
658    pub fn qname(&self, id: NodeId) -> String {
659        match self.prefix(id) {
660            Some(p) => format!("{}:{}", p, self.name(id)),
661            None => self.name(id).to_string(),
662        }
663    }
664
665    pub fn children(&self, id: NodeId) -> NodeIter<'_> {
666        NodeIter {
667            doc: self,
668            next: self.first_child(id),
669        }
670    }
671
672    pub fn attrs(&self, id: NodeId) -> NodeIter<'_> {
673        NodeIter {
674            doc: self,
675            next: self.first_attr(id),
676        }
677    }
678
679    pub fn len(&self) -> usize {
680        self.nodes.len()
681    }
682}
683
684/// Sibling iterator.
685pub struct NodeIter<'a> {
686    doc: &'a XmlDoc,
687    next: Option<NodeId>,
688}
689
690impl Iterator for NodeIter<'_> {
691    type Item = NodeId;
692
693    fn next(&mut self) -> Option<Self::Item> {
694        let n = self.next?;
695        self.next = self.doc.next_sibling(n);
696        Some(n)
697    }
698}
699
700/// `xmlFreeDoc` is `Drop`.
701#[doc(alias = "xmlFreeDoc")]
702pub fn xml_free_doc(_doc: XmlDoc) {}
703
704impl XmlDoc {
705    /// Deep-copy every child of `src_parent` in `src` under `dst_parent` here.
706    ///
707    /// Needed because an entity whose replacement text contains markup has to
708    /// become NODES, not the escaped text of that markup. `<!ENTITY e
709    /// "<b>x</b>">` used in content produced the literal string `<b>x</b>` in
710    /// the tree, so anything reading the document for structure got garbage
711    /// and DTD validation saw character data where an element was declared.
712    ///
713    /// Iterative, like every other traversal here: the replacement is
714    /// attacker-supplied and may be arbitrarily deep.
715    pub fn xml_copy_children_from(
716        &mut self,
717        src: &XmlDoc,
718        src_parent: NodeId,
719        dst_parent: NodeId,
720    ) {
721        // (source node, destination parent), pushed so they pop in order.
722        let mut stack: Vec<(NodeId, NodeId)> = Vec::new();
723        let mut c = src.last_child(src_parent);
724        while let Some(x) = c {
725            stack.push((x, dst_parent));
726            c = src.prev_sibling(x);
727        }
728        while let Some((s, parent)) = stack.pop() {
729            let n = src.node(s);
730            let copy = self.alloc(n.kind, n.name.clone());
731            {
732                let d = self.node_mut(copy);
733                d.prefix = n.prefix.clone();
734                d.ns_uri = n.ns_uri.clone();
735                d.content = n.content.clone();
736                d.ns_defs = n.ns_defs.clone();
737            }
738            self.xml_add_child(parent, copy);
739            // Attributes are a separate chain, not children.
740            let mut a = src.first_attr(s);
741            while let Some(x) = a {
742                let an = src.node(x);
743                let (nm, pre, val, uri) = (
744                    an.name.clone(),
745                    an.prefix.clone(),
746                    an.content.clone(),
747                    an.ns_uri.clone(),
748                );
749                let ac = self.add_attr_owned(copy, nm, pre, val);
750                self.node_mut(ac).ns_uri = uri;
751                a = src.next_sibling(x);
752            }
753            let mut k = src.last_child(s);
754            while let Some(x) = k {
755                stack.push((x, copy));
756                k = src.prev_sibling(x);
757            }
758        }
759    }
760}