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 elements: HashMap<String, ElementDecl>,
51 pub duplicate_elements: Vec<String>,
56 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#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
86pub struct NodeId(pub u32);
87
88impl NodeId {
89 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 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#[derive(Clone, Debug)]
139pub struct XmlDoc {
140 nodes: Vec<Node>,
141 pub version: String,
143 pub encoding: Option<String>,
145 pub standalone: Option<bool>,
147 root: Option<NodeId>,
149 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 #[doc(alias = "xmlNewDoc")]
162 pub fn xml_new_doc(version: Option<&str>) -> Self {
163 Self::with_node_capacity(version, 1)
164 }
165
166 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 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 pub fn reserve_nodes(&mut self, n: usize) {
191 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 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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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
684pub 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#[doc(alias = "xmlFreeDoc")]
702pub fn xml_free_doc(_doc: XmlDoc) {}
703
704impl XmlDoc {
705 pub fn xml_copy_children_from(
716 &mut self,
717 src: &XmlDoc,
718 src_parent: NodeId,
719 dst_parent: NodeId,
720 ) {
721 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 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}