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 attributes: HashMap<(String, String), AttrDecl>,
53}
54
55#[derive(Clone, Debug)]
56pub enum ElementDecl {
57 Empty,
58 Any,
59 Mixed(Vec<String>),
60 Children(String),
61}
62
63#[derive(Clone, Debug)]
64pub struct AttrDecl {
65 pub att_type: String,
66 pub default: AttrDefault,
67 pub default_value: Option<String>,
68 pub enumerated: Vec<String>,
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum AttrDefault {
73 Required,
74 Implied,
75 Fixed,
76 Value,
77}
78
79#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
81pub struct NodeId(pub u32);
82
83impl NodeId {
84 pub const DOCUMENT: NodeId = NodeId(0);
86
87 pub fn index(self) -> usize {
88 self.0 as usize
89 }
90}
91
92
93
94#[derive(Clone, Debug)]
95pub struct Node {
96 pub kind: NodeKind,
97 pub name: String,
98 pub prefix: Option<String>,
99 pub ns_uri: Option<String>,
100 pub content: String,
101 pub parent: Option<NodeId>,
102 pub first_child: Option<NodeId>,
103 pub last_child: Option<NodeId>,
104 pub prev_sibling: Option<NodeId>,
105 pub next_sibling: Option<NodeId>,
106 pub first_attr: Option<NodeId>,
107 pub last_attr: Option<NodeId>,
108 pub ns_defs: Vec<(Option<String>, String)>,
110}
111
112impl Node {
113 fn new(kind: NodeKind, name: String) -> Self {
114 Self {
115 kind,
116 name,
117 prefix: None,
118 ns_uri: None,
119 content: String::new(),
120 parent: None,
121 first_child: None,
122 last_child: None,
123 prev_sibling: None,
124 next_sibling: None,
125 first_attr: None,
126 last_attr: None,
127 ns_defs: Vec::new(),
128 }
129 }
130}
131
132#[derive(Clone, Debug)]
134pub struct XmlDoc {
135 nodes: Vec<Node>,
136 pub version: String,
138 pub encoding: Option<String>,
140 pub standalone: Option<bool>,
142 root: Option<NodeId>,
144 pub dtd: Option<XmlDtd>,
146}
147
148impl Default for XmlDoc {
149 fn default() -> Self {
150 Self::xml_new_doc(Some("1.0"))
151 }
152}
153
154impl XmlDoc {
155 #[doc(alias = "xmlNewDoc")]
157 pub fn xml_new_doc(version: Option<&str>) -> Self {
158 Self::with_node_capacity(version, 1)
159 }
160
161 pub fn with_node_capacity(version: Option<&str>, cap: usize) -> Self {
166 const MAX_ARENA_BYTES: usize = 32 << 20;
167 let ceiling = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
168 let mut nodes = Vec::with_capacity(cap.clamp(4, ceiling));
171 nodes.push(Node::new(NodeKind::Document, String::new()));
172 Self {
173 nodes,
174 version: version.unwrap_or("1.0").to_string(),
175 encoding: None,
176 standalone: None,
177 root: None,
178 dtd: None,
179 }
180 }
181
182 pub fn reserve_nodes(&mut self, n: usize) {
186 const MAX_ARENA_BYTES: usize = 32 << 20;
194 let cap = MAX_ARENA_BYTES / std::mem::size_of::<Node>();
195 self.nodes.reserve(n.min(cap));
196 }
197
198 pub fn node(&self, id: NodeId) -> &Node {
199 &self.nodes[id.index()]
200 }
201
202 pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
203 &mut self.nodes[id.index()]
204 }
205
206 pub fn kind(&self, id: NodeId) -> NodeKind {
207 self.node(id).kind
208 }
209
210 pub fn name(&self, id: NodeId) -> &str {
211 let n = self.node(id);
212 if n.name.is_empty() {
213 return match n.kind {
217 NodeKind::Text => "#text",
218 NodeKind::CData => "#cdata-section",
219 NodeKind::Comment => "#comment",
220 NodeKind::Document => "#document",
221 _ => "",
222 };
223 }
224 &n.name
225 }
226
227 pub fn prefix(&self, id: NodeId) -> Option<&str> {
228 self.node(id).prefix.as_deref()
229 }
230
231 pub fn ns_uri(&self, id: NodeId) -> Option<&str> {
232 self.node(id).ns_uri.as_deref()
233 }
234
235 pub fn content(&self, id: NodeId) -> &str {
236 &self.node(id).content
237 }
238
239 pub fn parent(&self, id: NodeId) -> Option<NodeId> {
240 self.node(id).parent
241 }
242
243 pub fn first_child(&self, id: NodeId) -> Option<NodeId> {
244 self.node(id).first_child
245 }
246
247 pub fn last_child(&self, id: NodeId) -> Option<NodeId> {
248 self.node(id).last_child
249 }
250
251 pub fn next_sibling(&self, id: NodeId) -> Option<NodeId> {
252 self.node(id).next_sibling
253 }
254
255 pub fn prev_sibling(&self, id: NodeId) -> Option<NodeId> {
256 self.node(id).prev_sibling
257 }
258
259 pub fn first_attr(&self, id: NodeId) -> Option<NodeId> {
260 self.node(id).first_attr
261 }
262
263 pub fn ns_defs(&self, id: NodeId) -> &[(Option<String>, String)] {
264 &self.node(id).ns_defs
265 }
266
267 pub fn alloc_unnamed(&mut self, kind: NodeKind) -> NodeId {
270 let id = NodeId(self.nodes.len() as u32);
271 self.nodes.push(Node::new(kind, String::new()));
272 id
273 }
274
275 pub fn alloc(&mut self, kind: NodeKind, name: impl Into<String>) -> NodeId {
276 let id = NodeId(self.nodes.len() as u32);
277 self.nodes.push(Node::new(kind, name.into()));
278 id
279 }
280
281 #[doc(alias = "xmlDocGetRootElement")]
283 pub fn xml_doc_get_root_element(&self) -> Option<NodeId> {
284 if let Some(r) = self.root {
285 return Some(r);
286 }
287 let mut c = self.first_child(NodeId::DOCUMENT);
288 while let Some(id) = c {
289 if self.kind(id) == NodeKind::Element {
290 return Some(id);
291 }
292 c = self.next_sibling(id);
293 }
294 None
295 }
296
297 #[doc(alias = "xmlDocSetRootElement")]
299 pub fn xml_doc_set_root_element(&mut self, elem: NodeId) -> Option<NodeId> {
300 let prev = self.xml_doc_get_root_element();
301 if let Some(p) = prev {
302 self.xml_unlink_node(p);
303 }
304 self.xml_add_child(NodeId::DOCUMENT, elem);
305 self.root = Some(elem);
306 prev
307 }
308
309 #[doc(alias = "xmlNewNode")]
311 pub fn xml_new_node(&mut self, ns_uri: Option<&str>, name: &str) -> NodeId {
312 let id = self.alloc(NodeKind::Element, name);
313 self.node_mut(id).ns_uri = ns_uri.map(str::to_string);
314 id
315 }
316
317 #[doc(alias = "xmlNewDocNode")]
319 pub fn xml_new_doc_node(
320 &mut self,
321 ns_uri: Option<&str>,
322 name: &str,
323 content: Option<&str>,
324 ) -> NodeId {
325 let id = self.xml_new_node(ns_uri, name);
326 if let Some(c) = content {
327 if !c.is_empty() {
328 let t = self.alloc(NodeKind::Text, "#text");
329 self.node_mut(t).content = c.to_string();
330 self.xml_add_child(id, t);
331 }
332 }
333 id
334 }
335
336 #[doc(alias = "xmlNewChild")]
338 pub fn xml_new_child(
339 &mut self,
340 parent: NodeId,
341 ns_uri: Option<&str>,
342 name: &str,
343 content: Option<&str>,
344 ) -> NodeId {
345 let id = self.xml_new_doc_node(ns_uri, name, content);
346 self.xml_add_child(parent, id);
347 id
348 }
349
350 #[doc(alias = "xmlAddChild")]
352 pub fn xml_add_child(&mut self, parent: NodeId, child: NodeId) {
353 if child == parent {
354 return;
355 }
356 self.xml_unlink_node(child);
357 self.node_mut(child).parent = Some(parent);
358 let last = self.node(parent).last_child;
359 if let Some(l) = last {
360 self.node_mut(l).next_sibling = Some(child);
361 self.node_mut(child).prev_sibling = Some(l);
362 } else {
363 self.node_mut(parent).first_child = Some(child);
364 }
365 self.node_mut(parent).last_child = Some(child);
366 if parent == NodeId::DOCUMENT && self.kind(child) == NodeKind::Element {
367 self.root = Some(child);
368 }
369 }
370
371 #[doc(alias = "xmlAddNextSibling")]
373 pub fn xml_add_next_sibling(&mut self, cur: NodeId, elem: NodeId) {
374 self.xml_unlink_node(elem);
375 let parent = self.node(cur).parent;
376 let next = self.node(cur).next_sibling;
377 self.node_mut(elem).parent = parent;
378 self.node_mut(elem).prev_sibling = Some(cur);
379 self.node_mut(elem).next_sibling = next;
380 self.node_mut(cur).next_sibling = Some(elem);
381 if let Some(n) = next {
382 self.node_mut(n).prev_sibling = Some(elem);
383 } else if let Some(p) = parent {
384 self.node_mut(p).last_child = Some(elem);
385 }
386 }
387
388 #[doc(alias = "xmlAddPrevSibling")]
390 pub fn xml_add_prev_sibling(&mut self, cur: NodeId, elem: NodeId) {
391 self.xml_unlink_node(elem);
392 let parent = self.node(cur).parent;
393 let prev = self.node(cur).prev_sibling;
394 self.node_mut(elem).parent = parent;
395 self.node_mut(elem).next_sibling = Some(cur);
396 self.node_mut(elem).prev_sibling = prev;
397 self.node_mut(cur).prev_sibling = Some(elem);
398 if let Some(p) = prev {
399 self.node_mut(p).next_sibling = Some(elem);
400 } else if let Some(par) = parent {
401 self.node_mut(par).first_child = Some(elem);
402 }
403 }
404
405 #[doc(alias = "xmlUnlinkNode")]
407 pub fn xml_unlink_node(&mut self, id: NodeId) {
408 if id == NodeId::DOCUMENT {
409 return;
410 }
411 let parent = self.node(id).parent;
412 let prev = self.node(id).prev_sibling;
413 let next = self.node(id).next_sibling;
414 if let Some(p) = prev {
415 self.node_mut(p).next_sibling = next;
416 }
417 if let Some(n) = next {
418 self.node_mut(n).prev_sibling = prev;
419 }
420 if let Some(par) = parent {
421 if self.node(par).first_child == Some(id) {
422 self.node_mut(par).first_child = next;
423 }
424 if self.node(par).last_child == Some(id) {
425 self.node_mut(par).last_child = prev;
426 }
427 }
428 if self.root == Some(id) {
429 self.root = None;
430 }
431 self.node_mut(id).parent = None;
432 self.node_mut(id).prev_sibling = None;
433 self.node_mut(id).next_sibling = None;
434 }
435
436 #[doc(alias = "xmlReplaceNode")]
438 pub fn xml_replace_node(&mut self, old: NodeId, new: NodeId) -> NodeId {
439 self.xml_add_next_sibling(old, new);
440 self.xml_unlink_node(old);
441 new
442 }
443
444 pub fn add_attr_owned(
448 &mut self,
449 elem: NodeId,
450 name: String,
451 prefix: Option<String>,
452 value: String,
453 ) -> NodeId {
454 let id = self.alloc(NodeKind::Attribute, name);
455 self.node_mut(id).prefix = prefix;
456 self.node_mut(id).content = value;
457 self.node_mut(id).parent = Some(elem);
458 let last = self.node(elem).last_attr;
459 if let Some(l) = last {
460 self.node_mut(l).next_sibling = Some(id);
461 self.node_mut(id).prev_sibling = Some(l);
462 } else {
463 self.node_mut(elem).first_attr = Some(id);
464 }
465 self.node_mut(elem).last_attr = Some(id);
466 id
467 }
468
469 pub fn add_attr(&mut self, elem: NodeId, name: &str, prefix: Option<&str>, value: &str) -> NodeId {
470 let id = self.alloc(NodeKind::Attribute, name);
471 self.node_mut(id).prefix = prefix.map(str::to_string);
472 self.node_mut(id).content = value.to_string();
473 self.node_mut(id).parent = Some(elem);
474 let last = self.node(elem).last_attr;
475 if let Some(l) = last {
476 self.node_mut(l).next_sibling = Some(id);
477 self.node_mut(id).prev_sibling = Some(l);
478 } else {
479 self.node_mut(elem).first_attr = Some(id);
480 }
481 self.node_mut(elem).last_attr = Some(id);
482 id
483 }
484
485 pub fn push_ns_def(&mut self, elem: NodeId, prefix: Option<String>, uri: String) {
486 self.node_mut(elem).ns_defs.push((prefix, uri));
487 }
488
489 #[doc(alias = "xmlSetProp")]
491 pub fn xml_set_prop(&mut self, node: NodeId, name: &str, value: &str) -> NodeId {
492 let mut a = self.first_attr(node);
493 while let Some(id) = a {
494 if self.node(id).prefix.is_none() && self.node(id).name == name {
495 self.node_mut(id).content = value.to_string();
496 return id;
497 }
498 a = self.next_sibling(id);
499 }
500 self.add_attr(node, name, None, value)
501 }
502
503 #[doc(alias = "xmlGetProp")]
505 pub fn xml_get_prop(&self, node: NodeId, name: &str) -> Option<String> {
506 let mut a = self.first_attr(node);
507 while let Some(id) = a {
508 if self.node(id).prefix.is_none() && self.node(id).name == name {
509 return Some(self.node(id).content.clone());
510 }
511 a = self.next_sibling(id);
512 }
513 None
514 }
515
516 #[doc(alias = "xmlHasProp")]
518 pub fn xml_has_prop(&self, node: NodeId, name: &str) -> bool {
519 self.xml_get_prop(node, name).is_some()
520 }
521
522 #[doc(alias = "xmlUnsetProp")]
524 pub fn xml_unset_prop(&mut self, node: NodeId, name: &str) -> bool {
525 let mut a = self.first_attr(node);
526 let mut prev: Option<NodeId> = None;
527 while let Some(id) = a {
528 let next = self.next_sibling(id);
529 if self.node(id).prefix.is_none() && self.node(id).name == name {
530 if let Some(p) = prev {
531 self.node_mut(p).next_sibling = next;
532 } else {
533 self.node_mut(node).first_attr = next;
534 }
535 if next.is_none() {
536 self.node_mut(node).last_attr = prev;
537 }
538 if let Some(n) = next {
539 self.node_mut(n).prev_sibling = prev;
540 }
541 self.node_mut(id).parent = None;
542 self.node_mut(id).prev_sibling = None;
543 self.node_mut(id).next_sibling = None;
544 return true;
545 }
546 prev = Some(id);
547 a = next;
548 }
549 false
550 }
551
552 #[doc(alias = "xmlNodeGetContent")]
554 pub fn xml_node_get_content(&self, id: NodeId) -> String {
555 match self.kind(id) {
556 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
557 self.content(id).to_string()
558 }
559 _ => {
560 let mut out = String::new();
561 self.collect_text(id, &mut out);
562 out
563 }
564 }
565 }
566
567 fn collect_text(&self, id: NodeId, out: &mut String) {
568 let mut c = self.first_child(id);
569 while let Some(ch) = c {
570 match self.kind(ch) {
571 NodeKind::Text | NodeKind::CData => out.push_str(self.content(ch)),
572 NodeKind::Element => self.collect_text(ch, out),
573 _ => {}
574 }
575 c = self.next_sibling(ch);
576 }
577 }
578
579 #[doc(alias = "xmlNodeSetContent")]
581 pub fn xml_node_set_content(&mut self, id: NodeId, content: &str) {
582 match self.kind(id) {
583 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
584 self.node_mut(id).content = content.to_string();
585 }
586 _ => {
587 let mut c = self.first_child(id);
588 while let Some(ch) = c {
589 let next = self.next_sibling(ch);
590 self.xml_unlink_node(ch);
591 c = next;
592 }
593 if !content.is_empty() {
594 let t = self.alloc(NodeKind::Text, "#text");
595 self.node_mut(t).content = content.to_string();
596 self.xml_add_child(id, t);
597 }
598 }
599 }
600 }
601
602 #[doc(alias = "xmlIsBlankNode")]
604 pub fn xml_is_blank_node(&self, id: NodeId) -> bool {
605 match self.kind(id) {
606 NodeKind::Text | NodeKind::CData => self.content(id).chars().all(|c| {
607 c == ' ' || c == '\t' || c == '\n' || c == '\r'
608 }),
609 _ => false,
610 }
611 }
612
613 #[doc(alias = "xmlSearchNs")]
615 pub fn xml_search_ns(&self, node: NodeId, prefix: Option<&str>) -> Option<String> {
616 if prefix == Some("xml") {
617 return Some("http://www.w3.org/XML/1998/namespace".into());
618 }
619 if prefix == Some("xmlns") {
620 return Some("http://www.w3.org/2000/xmlns/".into());
621 }
622 let mut cur = Some(node);
623 while let Some(id) = cur {
624 for (p, uri) in self.ns_defs(id) {
625 if p.as_deref() == prefix {
626 return Some(uri.clone());
627 }
628 }
629 cur = self.parent(id);
630 }
631 None
632 }
633
634 #[doc(alias = "xmlNewNs")]
636 pub fn xml_new_ns(&mut self, node: NodeId, href: &str, prefix: Option<&str>) {
637 self.push_ns_def(node, prefix.map(str::to_string), href.to_string());
638 }
639
640 #[doc(alias = "xmlSetNs")]
642 pub fn xml_set_ns(&mut self, node: NodeId, href: Option<&str>, prefix: Option<&str>) {
643 self.node_mut(node).ns_uri = href.map(str::to_string);
644 self.node_mut(node).prefix = prefix.map(str::to_string);
645 }
646
647 #[doc(alias = "xmlCopyDoc")]
649 pub fn xml_copy_doc(&self) -> XmlDoc {
650 self.clone()
651 }
652
653 pub fn qname(&self, id: NodeId) -> String {
654 match self.prefix(id) {
655 Some(p) => format!("{}:{}", p, self.name(id)),
656 None => self.name(id).to_string(),
657 }
658 }
659
660 pub fn children(&self, id: NodeId) -> NodeIter<'_> {
661 NodeIter {
662 doc: self,
663 next: self.first_child(id),
664 }
665 }
666
667 pub fn attrs(&self, id: NodeId) -> NodeIter<'_> {
668 NodeIter {
669 doc: self,
670 next: self.first_attr(id),
671 }
672 }
673
674 pub fn len(&self) -> usize {
675 self.nodes.len()
676 }
677}
678
679pub struct NodeIter<'a> {
681 doc: &'a XmlDoc,
682 next: Option<NodeId>,
683}
684
685impl Iterator for NodeIter<'_> {
686 type Item = NodeId;
687
688 fn next(&mut self) -> Option<Self::Item> {
689 let n = self.next?;
690 self.next = self.doc.next_sibling(n);
691 Some(n)
692 }
693}
694
695#[doc(alias = "xmlFreeDoc")]
697pub fn xml_free_doc(_doc: XmlDoc) {}
698
699impl XmlDoc {
700 pub fn xml_copy_children_from(
711 &mut self,
712 src: &XmlDoc,
713 src_parent: NodeId,
714 dst_parent: NodeId,
715 ) {
716 let mut stack: Vec<(NodeId, NodeId)> = Vec::new();
718 let mut c = src.last_child(src_parent);
719 while let Some(x) = c {
720 stack.push((x, dst_parent));
721 c = src.prev_sibling(x);
722 }
723 while let Some((s, parent)) = stack.pop() {
724 let n = src.node(s);
725 let copy = self.alloc(n.kind, n.name.clone());
726 {
727 let d = self.node_mut(copy);
728 d.prefix = n.prefix.clone();
729 d.ns_uri = n.ns_uri.clone();
730 d.content = n.content.clone();
731 d.ns_defs = n.ns_defs.clone();
732 }
733 self.xml_add_child(parent, copy);
734 let mut a = src.first_attr(s);
736 while let Some(x) = a {
737 let an = src.node(x);
738 let (nm, pre, val, uri) = (
739 an.name.clone(),
740 an.prefix.clone(),
741 an.content.clone(),
742 an.ns_uri.clone(),
743 );
744 let ac = self.add_attr_owned(copy, nm, pre, val);
745 self.node_mut(ac).ns_uri = uri;
746 a = src.next_sibling(x);
747 }
748 let mut k = src.last_child(s);
749 while let Some(x) = k {
750 stack.push((x, copy));
751 k = src.prev_sibling(x);
752 }
753 }
754 }
755}