1#![forbid(unsafe_code)]
5
6use std::collections::HashMap;
7
8#[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#[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 pub entities: HashMap<String, String>,
43 pub parameter_entities: HashMap<String, String>,
45 pub unparsed_entities: std::collections::HashSet<String>,
49 pub notations: std::collections::HashSet<String>,
53 pub ndata_notations: Vec<String>,
57 pub has_parameter_entity_refs: bool,
62 pub elements: HashMap<String, ElementDecl>,
64 pub duplicate_elements: Vec<String>,
69 pub attributes: HashMap<(String, String), AttrDecl>,
71}
72
73#[derive(Clone, Debug)]
74pub enum ElementDecl {
75 Empty,
76 Any,
77 Mixed(Vec<String>),
78 Children(String),
79}
80
81#[derive(Clone, Debug)]
82pub struct AttrDecl {
83 pub att_type: String,
84 pub default: AttrDefault,
85 pub default_value: Option<String>,
86 pub enumerated: Vec<String>,
87}
88
89#[derive(Clone, Copy, Debug, PartialEq, Eq)]
90pub enum AttrDefault {
91 Required,
92 Implied,
93 Fixed,
94 Value,
95}
96
97#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
99pub struct NodeId(pub u32);
100
101impl NodeId {
102 pub const DOCUMENT: NodeId = NodeId(0);
104
105 pub fn index(self) -> usize {
106 self.0 as usize
107 }
108}
109
110
111
112#[derive(Clone, Debug)]
113pub struct Node {
114 pub kind: NodeKind,
115 pub name: String,
116 pub prefix: Option<String>,
117 pub ns_uri: Option<String>,
118 pub content: String,
119 pub parent: Option<NodeId>,
120 pub first_child: Option<NodeId>,
121 pub last_child: Option<NodeId>,
122 pub prev_sibling: Option<NodeId>,
123 pub next_sibling: Option<NodeId>,
124 pub first_attr: Option<NodeId>,
125 pub last_attr: Option<NodeId>,
126 pub ns_defs: Vec<(Option<String>, String)>,
128}
129
130impl Node {
131 fn new(kind: NodeKind, name: String) -> Self {
132 Self {
133 kind,
134 name,
135 prefix: None,
136 ns_uri: None,
137 content: String::new(),
138 parent: None,
139 first_child: None,
140 last_child: None,
141 prev_sibling: None,
142 next_sibling: None,
143 first_attr: None,
144 last_attr: None,
145 ns_defs: Vec::new(),
146 }
147 }
148}
149
150#[derive(Clone, Debug)]
152pub struct XmlDoc {
153 nodes: Vec<Node>,
154 pub version: String,
156 pub encoding: Option<String>,
158 pub standalone: Option<bool>,
160 root: Option<NodeId>,
162 pub dtd: Option<XmlDtd>,
164 pub undeclared_entity_refs: Vec<String>,
168 pub reference_text: std::collections::HashSet<NodeId>,
175 pub elements_with_entity_refs: std::collections::HashSet<NodeId>,
179}
180
181impl Default for XmlDoc {
182 fn default() -> Self {
183 Self::xml_new_doc(Some("1.0"))
184 }
185}
186
187impl XmlDoc {
188 #[doc(alias = "xmlNewDoc")]
190 pub fn xml_new_doc(version: Option<&str>) -> Self {
191 Self::with_node_capacity(version, 1)
192 }
193
194 pub fn with_node_capacity(version: Option<&str>, cap: usize) -> Self {
199 const MAX_ARENA_BYTES: usize = 32 << 20;
200 let ceiling = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
201 let mut nodes = Vec::with_capacity(cap.clamp(4, ceiling));
204 nodes.push(Node::new(NodeKind::Document, String::new()));
205 Self {
206 nodes,
207 version: version.unwrap_or("1.0").to_string(),
208 encoding: None,
209 standalone: None,
210 root: None,
211 dtd: None,
212 undeclared_entity_refs: Vec::new(),
213 reference_text: Default::default(),
214 elements_with_entity_refs: Default::default(),
215 }
216 }
217
218 pub fn reserve_nodes(&mut self, n: usize) {
222 const MAX_ARENA_BYTES: usize = 32 << 20;
230 let cap = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
231 self.nodes.reserve(n.min(cap));
232 }
233
234 pub fn node(&self, id: NodeId) -> &Node {
235 &self.nodes[id.index()]
236 }
237
238 pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
239 &mut self.nodes[id.index()]
240 }
241
242 pub fn kind(&self, id: NodeId) -> NodeKind {
243 self.node(id).kind
244 }
245
246 pub fn name(&self, id: NodeId) -> &str {
247 let n = self.node(id);
248 if n.name.is_empty() {
249 return match n.kind {
253 NodeKind::Text => "#text",
254 NodeKind::CData => "#cdata-section",
255 NodeKind::Comment => "#comment",
256 NodeKind::Document => "#document",
257 _ => "",
258 };
259 }
260 &n.name
261 }
262
263 pub fn prefix(&self, id: NodeId) -> Option<&str> {
264 self.node(id).prefix.as_deref()
265 }
266
267 pub fn ns_uri(&self, id: NodeId) -> Option<&str> {
268 self.node(id).ns_uri.as_deref()
269 }
270
271 pub fn content(&self, id: NodeId) -> &str {
272 &self.node(id).content
273 }
274
275 pub fn parent(&self, id: NodeId) -> Option<NodeId> {
276 self.node(id).parent
277 }
278
279 pub fn first_child(&self, id: NodeId) -> Option<NodeId> {
280 self.node(id).first_child
281 }
282
283 pub fn last_child(&self, id: NodeId) -> Option<NodeId> {
284 self.node(id).last_child
285 }
286
287 pub fn next_sibling(&self, id: NodeId) -> Option<NodeId> {
288 self.node(id).next_sibling
289 }
290
291 pub fn prev_sibling(&self, id: NodeId) -> Option<NodeId> {
292 self.node(id).prev_sibling
293 }
294
295 pub fn first_attr(&self, id: NodeId) -> Option<NodeId> {
296 self.node(id).first_attr
297 }
298
299 pub fn ns_defs(&self, id: NodeId) -> &[(Option<String>, String)] {
300 &self.node(id).ns_defs
301 }
302
303 pub fn alloc_unnamed(&mut self, kind: NodeKind) -> NodeId {
306 let id = NodeId(self.nodes.len() as u32);
307 self.nodes.push(Node::new(kind, String::new()));
308 id
309 }
310
311 pub fn alloc(&mut self, kind: NodeKind, name: impl Into<String>) -> NodeId {
312 let id = NodeId(self.nodes.len() as u32);
313 self.nodes.push(Node::new(kind, name.into()));
314 id
315 }
316
317 #[doc(alias = "xmlDocGetRootElement")]
319 pub fn xml_doc_get_root_element(&self) -> Option<NodeId> {
320 if let Some(r) = self.root {
321 return Some(r);
322 }
323 let mut c = self.first_child(NodeId::DOCUMENT);
324 while let Some(id) = c {
325 if self.kind(id) == NodeKind::Element {
326 return Some(id);
327 }
328 c = self.next_sibling(id);
329 }
330 None
331 }
332
333 #[doc(alias = "xmlDocSetRootElement")]
335 pub fn xml_doc_set_root_element(&mut self, elem: NodeId) -> Option<NodeId> {
336 let prev = self.xml_doc_get_root_element();
337 if let Some(p) = prev {
338 self.xml_unlink_node(p);
339 }
340 self.xml_add_child(NodeId::DOCUMENT, elem);
341 self.root = Some(elem);
342 prev
343 }
344
345 #[doc(alias = "xmlNewNode")]
347 pub fn xml_new_node(&mut self, ns_uri: Option<&str>, name: &str) -> NodeId {
348 let id = self.alloc(NodeKind::Element, name);
349 self.node_mut(id).ns_uri = ns_uri.map(str::to_string);
350 id
351 }
352
353 #[doc(alias = "xmlNewDocNode")]
355 pub fn xml_new_doc_node(
356 &mut self,
357 ns_uri: Option<&str>,
358 name: &str,
359 content: Option<&str>,
360 ) -> NodeId {
361 let id = self.xml_new_node(ns_uri, name);
362 if let Some(c) = content {
363 if !c.is_empty() {
364 let t = self.alloc(NodeKind::Text, "#text");
365 self.node_mut(t).content = c.to_string();
366 self.xml_add_child(id, t);
367 }
368 }
369 id
370 }
371
372 #[doc(alias = "xmlNewChild")]
374 pub fn xml_new_child(
375 &mut self,
376 parent: NodeId,
377 ns_uri: Option<&str>,
378 name: &str,
379 content: Option<&str>,
380 ) -> NodeId {
381 let id = self.xml_new_doc_node(ns_uri, name, content);
382 self.xml_add_child(parent, id);
383 id
384 }
385
386 #[doc(alias = "xmlAddChild")]
388 pub fn xml_add_child(&mut self, parent: NodeId, child: NodeId) {
389 if child == parent {
390 return;
391 }
392 self.xml_unlink_node(child);
393 self.node_mut(child).parent = Some(parent);
394 let last = self.node(parent).last_child;
395 if let Some(l) = last {
396 self.node_mut(l).next_sibling = Some(child);
397 self.node_mut(child).prev_sibling = Some(l);
398 } else {
399 self.node_mut(parent).first_child = Some(child);
400 }
401 self.node_mut(parent).last_child = Some(child);
402 if parent == NodeId::DOCUMENT && self.kind(child) == NodeKind::Element {
403 self.root = Some(child);
404 }
405 }
406
407 #[doc(alias = "xmlAddNextSibling")]
409 pub fn xml_add_next_sibling(&mut self, cur: NodeId, elem: NodeId) {
410 self.xml_unlink_node(elem);
411 let parent = self.node(cur).parent;
412 let next = self.node(cur).next_sibling;
413 self.node_mut(elem).parent = parent;
414 self.node_mut(elem).prev_sibling = Some(cur);
415 self.node_mut(elem).next_sibling = next;
416 self.node_mut(cur).next_sibling = Some(elem);
417 if let Some(n) = next {
418 self.node_mut(n).prev_sibling = Some(elem);
419 } else if let Some(p) = parent {
420 self.node_mut(p).last_child = Some(elem);
421 }
422 }
423
424 #[doc(alias = "xmlAddPrevSibling")]
426 pub fn xml_add_prev_sibling(&mut self, cur: NodeId, elem: NodeId) {
427 self.xml_unlink_node(elem);
428 let parent = self.node(cur).parent;
429 let prev = self.node(cur).prev_sibling;
430 self.node_mut(elem).parent = parent;
431 self.node_mut(elem).next_sibling = Some(cur);
432 self.node_mut(elem).prev_sibling = prev;
433 self.node_mut(cur).prev_sibling = Some(elem);
434 if let Some(p) = prev {
435 self.node_mut(p).next_sibling = Some(elem);
436 } else if let Some(par) = parent {
437 self.node_mut(par).first_child = Some(elem);
438 }
439 }
440
441 #[doc(alias = "xmlUnlinkNode")]
443 pub fn xml_unlink_node(&mut self, id: NodeId) {
444 if id == NodeId::DOCUMENT {
445 return;
446 }
447 let parent = self.node(id).parent;
448 let prev = self.node(id).prev_sibling;
449 let next = self.node(id).next_sibling;
450 if let Some(p) = prev {
451 self.node_mut(p).next_sibling = next;
452 }
453 if let Some(n) = next {
454 self.node_mut(n).prev_sibling = prev;
455 }
456 if let Some(par) = parent {
457 if self.node(par).first_child == Some(id) {
458 self.node_mut(par).first_child = next;
459 }
460 if self.node(par).last_child == Some(id) {
461 self.node_mut(par).last_child = prev;
462 }
463 }
464 if self.root == Some(id) {
465 self.root = None;
466 }
467 self.node_mut(id).parent = None;
468 self.node_mut(id).prev_sibling = None;
469 self.node_mut(id).next_sibling = None;
470 }
471
472 #[doc(alias = "xmlReplaceNode")]
474 pub fn xml_replace_node(&mut self, old: NodeId, new: NodeId) -> NodeId {
475 self.xml_add_next_sibling(old, new);
476 self.xml_unlink_node(old);
477 new
478 }
479
480 pub fn add_attr_owned(
484 &mut self,
485 elem: NodeId,
486 name: String,
487 prefix: Option<String>,
488 value: String,
489 ) -> NodeId {
490 let id = self.alloc(NodeKind::Attribute, name);
491 self.node_mut(id).prefix = prefix;
492 self.node_mut(id).content = value;
493 self.node_mut(id).parent = Some(elem);
494 let last = self.node(elem).last_attr;
495 if let Some(l) = last {
496 self.node_mut(l).next_sibling = Some(id);
497 self.node_mut(id).prev_sibling = Some(l);
498 } else {
499 self.node_mut(elem).first_attr = Some(id);
500 }
501 self.node_mut(elem).last_attr = Some(id);
502 id
503 }
504
505 pub fn add_attr(&mut self, elem: NodeId, name: &str, prefix: Option<&str>, value: &str) -> NodeId {
506 let id = self.alloc(NodeKind::Attribute, name);
507 self.node_mut(id).prefix = prefix.map(str::to_string);
508 self.node_mut(id).content = value.to_string();
509 self.node_mut(id).parent = Some(elem);
510 let last = self.node(elem).last_attr;
511 if let Some(l) = last {
512 self.node_mut(l).next_sibling = Some(id);
513 self.node_mut(id).prev_sibling = Some(l);
514 } else {
515 self.node_mut(elem).first_attr = Some(id);
516 }
517 self.node_mut(elem).last_attr = Some(id);
518 id
519 }
520
521 pub fn push_ns_def(&mut self, elem: NodeId, prefix: Option<String>, uri: String) {
522 self.node_mut(elem).ns_defs.push((prefix, uri));
523 }
524
525 #[doc(alias = "xmlSetProp")]
527 pub fn xml_set_prop(&mut self, node: NodeId, name: &str, value: &str) -> NodeId {
528 let mut a = self.first_attr(node);
529 while let Some(id) = a {
530 if self.node(id).prefix.is_none() && self.node(id).name == name {
531 self.node_mut(id).content = value.to_string();
532 return id;
533 }
534 a = self.next_sibling(id);
535 }
536 self.add_attr(node, name, None, value)
537 }
538
539 #[doc(alias = "xmlGetProp")]
541 pub fn xml_get_prop(&self, node: NodeId, name: &str) -> Option<String> {
542 let mut a = self.first_attr(node);
543 while let Some(id) = a {
544 if self.node(id).prefix.is_none() && self.node(id).name == name {
545 return Some(self.node(id).content.clone());
546 }
547 a = self.next_sibling(id);
548 }
549 None
550 }
551
552 #[doc(alias = "xmlHasProp")]
554 pub fn xml_has_prop(&self, node: NodeId, name: &str) -> bool {
555 self.xml_get_prop(node, name).is_some()
556 }
557
558 #[doc(alias = "xmlUnsetProp")]
560 pub fn xml_unset_prop(&mut self, node: NodeId, name: &str) -> bool {
561 let mut a = self.first_attr(node);
562 let mut prev: Option<NodeId> = None;
563 while let Some(id) = a {
564 let next = self.next_sibling(id);
565 if self.node(id).prefix.is_none() && self.node(id).name == name {
566 if let Some(p) = prev {
567 self.node_mut(p).next_sibling = next;
568 } else {
569 self.node_mut(node).first_attr = next;
570 }
571 if next.is_none() {
572 self.node_mut(node).last_attr = prev;
573 }
574 if let Some(n) = next {
575 self.node_mut(n).prev_sibling = prev;
576 }
577 self.node_mut(id).parent = None;
578 self.node_mut(id).prev_sibling = None;
579 self.node_mut(id).next_sibling = None;
580 return true;
581 }
582 prev = Some(id);
583 a = next;
584 }
585 false
586 }
587
588 #[doc(alias = "xmlNodeGetContent")]
590 pub fn xml_node_get_content(&self, id: NodeId) -> String {
591 match self.kind(id) {
592 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
593 self.content(id).to_string()
594 }
595 _ => {
596 let mut out = String::new();
597 self.collect_text(id, &mut out);
598 out
599 }
600 }
601 }
602
603 fn collect_text(&self, id: NodeId, out: &mut String) {
604 let mut c = self.first_child(id);
605 while let Some(ch) = c {
606 match self.kind(ch) {
607 NodeKind::Text | NodeKind::CData => out.push_str(self.content(ch)),
608 NodeKind::Element => self.collect_text(ch, out),
609 _ => {}
610 }
611 c = self.next_sibling(ch);
612 }
613 }
614
615 #[doc(alias = "xmlNodeSetContent")]
617 pub fn xml_node_set_content(&mut self, id: NodeId, content: &str) {
618 match self.kind(id) {
619 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
620 self.node_mut(id).content = content.to_string();
621 }
622 _ => {
623 let mut c = self.first_child(id);
624 while let Some(ch) = c {
625 let next = self.next_sibling(ch);
626 self.xml_unlink_node(ch);
627 c = next;
628 }
629 if !content.is_empty() {
630 let t = self.alloc(NodeKind::Text, "#text");
631 self.node_mut(t).content = content.to_string();
632 self.xml_add_child(id, t);
633 }
634 }
635 }
636 }
637
638 #[doc(alias = "xmlIsBlankNode")]
640 pub fn xml_is_blank_node(&self, id: NodeId) -> bool {
641 match self.kind(id) {
642 NodeKind::Text | NodeKind::CData => self.content(id).chars().all(|c| {
643 c == ' ' || c == '\t' || c == '\n' || c == '\r'
644 }),
645 _ => false,
646 }
647 }
648
649 #[doc(alias = "xmlSearchNs")]
651 pub fn xml_search_ns(&self, node: NodeId, prefix: Option<&str>) -> Option<String> {
652 if prefix == Some("xml") {
653 return Some("http://www.w3.org/XML/1998/namespace".into());
654 }
655 if prefix == Some("xmlns") {
656 return Some("http://www.w3.org/2000/xmlns/".into());
657 }
658 let mut cur = Some(node);
659 while let Some(id) = cur {
660 for (p, uri) in self.ns_defs(id) {
661 if p.as_deref() == prefix {
662 return Some(uri.clone());
663 }
664 }
665 cur = self.parent(id);
666 }
667 None
668 }
669
670 #[doc(alias = "xmlNewNs")]
672 pub fn xml_new_ns(&mut self, node: NodeId, href: &str, prefix: Option<&str>) {
673 self.push_ns_def(node, prefix.map(str::to_string), href.to_string());
674 }
675
676 #[doc(alias = "xmlSetNs")]
678 pub fn xml_set_ns(&mut self, node: NodeId, href: Option<&str>, prefix: Option<&str>) {
679 self.node_mut(node).ns_uri = href.map(str::to_string);
680 self.node_mut(node).prefix = prefix.map(str::to_string);
681 }
682
683 #[doc(alias = "xmlCopyDoc")]
685 pub fn xml_copy_doc(&self) -> XmlDoc {
686 self.clone()
687 }
688
689 pub fn qname(&self, id: NodeId) -> String {
690 match self.prefix(id) {
691 Some(p) => format!("{}:{}", p, self.name(id)),
692 None => self.name(id).to_string(),
693 }
694 }
695
696 pub fn children(&self, id: NodeId) -> NodeIter<'_> {
697 NodeIter {
698 doc: self,
699 next: self.first_child(id),
700 }
701 }
702
703 pub fn attrs(&self, id: NodeId) -> NodeIter<'_> {
704 NodeIter {
705 doc: self,
706 next: self.first_attr(id),
707 }
708 }
709
710 pub fn len(&self) -> usize {
711 self.nodes.len()
712 }
713}
714
715pub struct NodeIter<'a> {
717 doc: &'a XmlDoc,
718 next: Option<NodeId>,
719}
720
721impl Iterator for NodeIter<'_> {
722 type Item = NodeId;
723
724 fn next(&mut self) -> Option<Self::Item> {
725 let n = self.next?;
726 self.next = self.doc.next_sibling(n);
727 Some(n)
728 }
729}
730
731#[doc(alias = "xmlFreeDoc")]
733pub fn xml_free_doc(_doc: XmlDoc) {}
734
735impl XmlDoc {
736 pub fn xml_copy_children_from(
747 &mut self,
748 src: &XmlDoc,
749 src_parent: NodeId,
750 dst_parent: NodeId,
751 ) {
752 let mut stack: Vec<(NodeId, NodeId)> = Vec::new();
754 let mut c = src.last_child(src_parent);
755 while let Some(x) = c {
756 stack.push((x, dst_parent));
757 c = src.prev_sibling(x);
758 }
759 while let Some((s, parent)) = stack.pop() {
760 let n = src.node(s);
761 let copy = self.alloc(n.kind, n.name.clone());
762 {
763 let d = self.node_mut(copy);
764 d.prefix = n.prefix.clone();
765 d.ns_uri = n.ns_uri.clone();
766 d.content = n.content.clone();
767 d.ns_defs = n.ns_defs.clone();
768 }
769 self.xml_add_child(parent, copy);
770 if src.reference_text.contains(&s) {
775 self.reference_text.insert(copy);
776 }
777 let mut a = src.first_attr(s);
779 while let Some(x) = a {
780 let an = src.node(x);
781 let (nm, pre, val, uri) = (
782 an.name.clone(),
783 an.prefix.clone(),
784 an.content.clone(),
785 an.ns_uri.clone(),
786 );
787 let ac = self.add_attr_owned(copy, nm, pre, val);
788 self.node_mut(ac).ns_uri = uri;
789 a = src.next_sibling(x);
790 }
791 let mut k = src.last_child(s);
792 while let Some(x) = k {
793 stack.push((x, copy));
794 k = src.prev_sibling(x);
795 }
796 }
797 }
798}