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