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#[derive(Clone, Debug)]
89pub struct Node {
90 pub kind: NodeKind,
91 pub name: String,
92 pub prefix: Option<String>,
93 pub ns_uri: Option<String>,
94 pub content: String,
95 pub parent: Option<NodeId>,
96 pub first_child: Option<NodeId>,
97 pub last_child: Option<NodeId>,
98 pub prev_sibling: Option<NodeId>,
99 pub next_sibling: Option<NodeId>,
100 pub first_attr: Option<NodeId>,
101 pub last_attr: Option<NodeId>,
102 pub ns_defs: Vec<(Option<String>, String)>,
104}
105
106impl Node {
107 fn new(kind: NodeKind, name: String) -> Self {
108 Self {
109 kind,
110 name,
111 prefix: None,
112 ns_uri: None,
113 content: String::new(),
114 parent: None,
115 first_child: None,
116 last_child: None,
117 prev_sibling: None,
118 next_sibling: None,
119 first_attr: None,
120 last_attr: None,
121 ns_defs: Vec::new(),
122 }
123 }
124}
125
126#[derive(Clone, Debug)]
128pub struct XmlDoc {
129 nodes: Vec<Node>,
130 pub version: String,
132 pub encoding: Option<String>,
134 pub standalone: Option<bool>,
136 root: Option<NodeId>,
138 pub dtd: Option<XmlDtd>,
140}
141
142impl Default for XmlDoc {
143 fn default() -> Self {
144 Self::xml_new_doc(Some("1.0"))
145 }
146}
147
148impl XmlDoc {
149 #[doc(alias = "xmlNewDoc")]
151 pub fn xml_new_doc(version: Option<&str>) -> Self {
152 let mut nodes = Vec::new();
153 nodes.push(Node::new(NodeKind::Document, "#document".into()));
154 Self {
155 nodes,
156 version: version.unwrap_or("1.0").to_string(),
157 encoding: None,
158 standalone: None,
159 root: None,
160 dtd: None,
161 }
162 }
163
164 pub fn node(&self, id: NodeId) -> &Node {
165 &self.nodes[id.index()]
166 }
167
168 pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
169 &mut self.nodes[id.index()]
170 }
171
172 pub fn kind(&self, id: NodeId) -> NodeKind {
173 self.node(id).kind
174 }
175
176 pub fn name(&self, id: NodeId) -> &str {
177 &self.node(id).name
178 }
179
180 pub fn prefix(&self, id: NodeId) -> Option<&str> {
181 self.node(id).prefix.as_deref()
182 }
183
184 pub fn ns_uri(&self, id: NodeId) -> Option<&str> {
185 self.node(id).ns_uri.as_deref()
186 }
187
188 pub fn content(&self, id: NodeId) -> &str {
189 &self.node(id).content
190 }
191
192 pub fn parent(&self, id: NodeId) -> Option<NodeId> {
193 self.node(id).parent
194 }
195
196 pub fn first_child(&self, id: NodeId) -> Option<NodeId> {
197 self.node(id).first_child
198 }
199
200 pub fn last_child(&self, id: NodeId) -> Option<NodeId> {
201 self.node(id).last_child
202 }
203
204 pub fn next_sibling(&self, id: NodeId) -> Option<NodeId> {
205 self.node(id).next_sibling
206 }
207
208 pub fn prev_sibling(&self, id: NodeId) -> Option<NodeId> {
209 self.node(id).prev_sibling
210 }
211
212 pub fn first_attr(&self, id: NodeId) -> Option<NodeId> {
213 self.node(id).first_attr
214 }
215
216 pub fn ns_defs(&self, id: NodeId) -> &[(Option<String>, String)] {
217 &self.node(id).ns_defs
218 }
219
220 pub fn alloc(&mut self, kind: NodeKind, name: impl Into<String>) -> NodeId {
221 let id = NodeId(self.nodes.len() as u32);
222 self.nodes.push(Node::new(kind, name.into()));
223 id
224 }
225
226 #[doc(alias = "xmlDocGetRootElement")]
228 pub fn xml_doc_get_root_element(&self) -> Option<NodeId> {
229 if let Some(r) = self.root {
230 return Some(r);
231 }
232 let mut c = self.first_child(NodeId::DOCUMENT);
233 while let Some(id) = c {
234 if self.kind(id) == NodeKind::Element {
235 return Some(id);
236 }
237 c = self.next_sibling(id);
238 }
239 None
240 }
241
242 #[doc(alias = "xmlDocSetRootElement")]
244 pub fn xml_doc_set_root_element(&mut self, elem: NodeId) -> Option<NodeId> {
245 let prev = self.xml_doc_get_root_element();
246 if let Some(p) = prev {
247 self.xml_unlink_node(p);
248 }
249 self.xml_add_child(NodeId::DOCUMENT, elem);
250 self.root = Some(elem);
251 prev
252 }
253
254 #[doc(alias = "xmlNewNode")]
256 pub fn xml_new_node(&mut self, ns_uri: Option<&str>, name: &str) -> NodeId {
257 let id = self.alloc(NodeKind::Element, name);
258 self.node_mut(id).ns_uri = ns_uri.map(str::to_string);
259 id
260 }
261
262 #[doc(alias = "xmlNewDocNode")]
264 pub fn xml_new_doc_node(
265 &mut self,
266 ns_uri: Option<&str>,
267 name: &str,
268 content: Option<&str>,
269 ) -> NodeId {
270 let id = self.xml_new_node(ns_uri, name);
271 if let Some(c) = content {
272 if !c.is_empty() {
273 let t = self.alloc(NodeKind::Text, "#text");
274 self.node_mut(t).content = c.to_string();
275 self.xml_add_child(id, t);
276 }
277 }
278 id
279 }
280
281 #[doc(alias = "xmlNewChild")]
283 pub fn xml_new_child(
284 &mut self,
285 parent: NodeId,
286 ns_uri: Option<&str>,
287 name: &str,
288 content: Option<&str>,
289 ) -> NodeId {
290 let id = self.xml_new_doc_node(ns_uri, name, content);
291 self.xml_add_child(parent, id);
292 id
293 }
294
295 #[doc(alias = "xmlAddChild")]
297 pub fn xml_add_child(&mut self, parent: NodeId, child: NodeId) {
298 if child == parent {
299 return;
300 }
301 self.xml_unlink_node(child);
302 self.node_mut(child).parent = Some(parent);
303 let last = self.node(parent).last_child;
304 if let Some(l) = last {
305 self.node_mut(l).next_sibling = Some(child);
306 self.node_mut(child).prev_sibling = Some(l);
307 } else {
308 self.node_mut(parent).first_child = Some(child);
309 }
310 self.node_mut(parent).last_child = Some(child);
311 if parent == NodeId::DOCUMENT && self.kind(child) == NodeKind::Element {
312 self.root = Some(child);
313 }
314 }
315
316 #[doc(alias = "xmlAddNextSibling")]
318 pub fn xml_add_next_sibling(&mut self, cur: NodeId, elem: NodeId) {
319 self.xml_unlink_node(elem);
320 let parent = self.node(cur).parent;
321 let next = self.node(cur).next_sibling;
322 self.node_mut(elem).parent = parent;
323 self.node_mut(elem).prev_sibling = Some(cur);
324 self.node_mut(elem).next_sibling = next;
325 self.node_mut(cur).next_sibling = Some(elem);
326 if let Some(n) = next {
327 self.node_mut(n).prev_sibling = Some(elem);
328 } else if let Some(p) = parent {
329 self.node_mut(p).last_child = Some(elem);
330 }
331 }
332
333 #[doc(alias = "xmlAddPrevSibling")]
335 pub fn xml_add_prev_sibling(&mut self, cur: NodeId, elem: NodeId) {
336 self.xml_unlink_node(elem);
337 let parent = self.node(cur).parent;
338 let prev = self.node(cur).prev_sibling;
339 self.node_mut(elem).parent = parent;
340 self.node_mut(elem).next_sibling = Some(cur);
341 self.node_mut(elem).prev_sibling = prev;
342 self.node_mut(cur).prev_sibling = Some(elem);
343 if let Some(p) = prev {
344 self.node_mut(p).next_sibling = Some(elem);
345 } else if let Some(par) = parent {
346 self.node_mut(par).first_child = Some(elem);
347 }
348 }
349
350 #[doc(alias = "xmlUnlinkNode")]
352 pub fn xml_unlink_node(&mut self, id: NodeId) {
353 if id == NodeId::DOCUMENT {
354 return;
355 }
356 let parent = self.node(id).parent;
357 let prev = self.node(id).prev_sibling;
358 let next = self.node(id).next_sibling;
359 if let Some(p) = prev {
360 self.node_mut(p).next_sibling = next;
361 }
362 if let Some(n) = next {
363 self.node_mut(n).prev_sibling = prev;
364 }
365 if let Some(par) = parent {
366 if self.node(par).first_child == Some(id) {
367 self.node_mut(par).first_child = next;
368 }
369 if self.node(par).last_child == Some(id) {
370 self.node_mut(par).last_child = prev;
371 }
372 }
373 if self.root == Some(id) {
374 self.root = None;
375 }
376 self.node_mut(id).parent = None;
377 self.node_mut(id).prev_sibling = None;
378 self.node_mut(id).next_sibling = None;
379 }
380
381 #[doc(alias = "xmlReplaceNode")]
383 pub fn xml_replace_node(&mut self, old: NodeId, new: NodeId) -> NodeId {
384 self.xml_add_next_sibling(old, new);
385 self.xml_unlink_node(old);
386 new
387 }
388
389 pub fn add_attr(&mut self, elem: NodeId, name: &str, prefix: Option<&str>, value: &str) -> NodeId {
390 let id = self.alloc(NodeKind::Attribute, name);
391 self.node_mut(id).prefix = prefix.map(str::to_string);
392 self.node_mut(id).content = value.to_string();
393 self.node_mut(id).parent = Some(elem);
394 let last = self.node(elem).last_attr;
395 if let Some(l) = last {
396 self.node_mut(l).next_sibling = Some(id);
397 self.node_mut(id).prev_sibling = Some(l);
398 } else {
399 self.node_mut(elem).first_attr = Some(id);
400 }
401 self.node_mut(elem).last_attr = Some(id);
402 id
403 }
404
405 pub fn push_ns_def(&mut self, elem: NodeId, prefix: Option<String>, uri: String) {
406 self.node_mut(elem).ns_defs.push((prefix, uri));
407 }
408
409 #[doc(alias = "xmlSetProp")]
411 pub fn xml_set_prop(&mut self, node: NodeId, name: &str, value: &str) -> NodeId {
412 let mut a = self.first_attr(node);
413 while let Some(id) = a {
414 if self.node(id).prefix.is_none() && self.node(id).name == name {
415 self.node_mut(id).content = value.to_string();
416 return id;
417 }
418 a = self.next_sibling(id);
419 }
420 self.add_attr(node, name, None, value)
421 }
422
423 #[doc(alias = "xmlGetProp")]
425 pub fn xml_get_prop(&self, node: NodeId, name: &str) -> Option<String> {
426 let mut a = self.first_attr(node);
427 while let Some(id) = a {
428 if self.node(id).prefix.is_none() && self.node(id).name == name {
429 return Some(self.node(id).content.clone());
430 }
431 a = self.next_sibling(id);
432 }
433 None
434 }
435
436 #[doc(alias = "xmlHasProp")]
438 pub fn xml_has_prop(&self, node: NodeId, name: &str) -> bool {
439 self.xml_get_prop(node, name).is_some()
440 }
441
442 #[doc(alias = "xmlUnsetProp")]
444 pub fn xml_unset_prop(&mut self, node: NodeId, name: &str) -> bool {
445 let mut a = self.first_attr(node);
446 let mut prev: Option<NodeId> = None;
447 while let Some(id) = a {
448 let next = self.next_sibling(id);
449 if self.node(id).prefix.is_none() && self.node(id).name == name {
450 if let Some(p) = prev {
451 self.node_mut(p).next_sibling = next;
452 } else {
453 self.node_mut(node).first_attr = next;
454 }
455 if next.is_none() {
456 self.node_mut(node).last_attr = prev;
457 }
458 if let Some(n) = next {
459 self.node_mut(n).prev_sibling = prev;
460 }
461 self.node_mut(id).parent = None;
462 self.node_mut(id).prev_sibling = None;
463 self.node_mut(id).next_sibling = None;
464 return true;
465 }
466 prev = Some(id);
467 a = next;
468 }
469 false
470 }
471
472 #[doc(alias = "xmlNodeGetContent")]
474 pub fn xml_node_get_content(&self, id: NodeId) -> String {
475 match self.kind(id) {
476 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
477 self.content(id).to_string()
478 }
479 _ => {
480 let mut out = String::new();
481 self.collect_text(id, &mut out);
482 out
483 }
484 }
485 }
486
487 fn collect_text(&self, id: NodeId, out: &mut String) {
488 let mut c = self.first_child(id);
489 while let Some(ch) = c {
490 match self.kind(ch) {
491 NodeKind::Text | NodeKind::CData => out.push_str(self.content(ch)),
492 NodeKind::Element => self.collect_text(ch, out),
493 _ => {}
494 }
495 c = self.next_sibling(ch);
496 }
497 }
498
499 #[doc(alias = "xmlNodeSetContent")]
501 pub fn xml_node_set_content(&mut self, id: NodeId, content: &str) {
502 match self.kind(id) {
503 NodeKind::Text | NodeKind::CData | NodeKind::Comment | NodeKind::Pi | NodeKind::Attribute => {
504 self.node_mut(id).content = content.to_string();
505 }
506 _ => {
507 let mut c = self.first_child(id);
508 while let Some(ch) = c {
509 let next = self.next_sibling(ch);
510 self.xml_unlink_node(ch);
511 c = next;
512 }
513 if !content.is_empty() {
514 let t = self.alloc(NodeKind::Text, "#text");
515 self.node_mut(t).content = content.to_string();
516 self.xml_add_child(id, t);
517 }
518 }
519 }
520 }
521
522 #[doc(alias = "xmlIsBlankNode")]
524 pub fn xml_is_blank_node(&self, id: NodeId) -> bool {
525 match self.kind(id) {
526 NodeKind::Text | NodeKind::CData => self.content(id).chars().all(|c| {
527 c == ' ' || c == '\t' || c == '\n' || c == '\r'
528 }),
529 _ => false,
530 }
531 }
532
533 #[doc(alias = "xmlSearchNs")]
535 pub fn xml_search_ns(&self, node: NodeId, prefix: Option<&str>) -> Option<String> {
536 if prefix == Some("xml") {
537 return Some("http://www.w3.org/XML/1998/namespace".into());
538 }
539 if prefix == Some("xmlns") {
540 return Some("http://www.w3.org/2000/xmlns/".into());
541 }
542 let mut cur = Some(node);
543 while let Some(id) = cur {
544 for (p, uri) in self.ns_defs(id) {
545 if p.as_deref() == prefix {
546 return Some(uri.clone());
547 }
548 }
549 cur = self.parent(id);
550 }
551 None
552 }
553
554 #[doc(alias = "xmlNewNs")]
556 pub fn xml_new_ns(&mut self, node: NodeId, href: &str, prefix: Option<&str>) {
557 self.push_ns_def(node, prefix.map(str::to_string), href.to_string());
558 }
559
560 #[doc(alias = "xmlSetNs")]
562 pub fn xml_set_ns(&mut self, node: NodeId, href: Option<&str>, prefix: Option<&str>) {
563 self.node_mut(node).ns_uri = href.map(str::to_string);
564 self.node_mut(node).prefix = prefix.map(str::to_string);
565 }
566
567 #[doc(alias = "xmlCopyDoc")]
569 pub fn xml_copy_doc(&self) -> XmlDoc {
570 self.clone()
571 }
572
573 pub fn qname(&self, id: NodeId) -> String {
574 match self.prefix(id) {
575 Some(p) => format!("{}:{}", p, self.name(id)),
576 None => self.name(id).to_string(),
577 }
578 }
579
580 pub fn children(&self, id: NodeId) -> NodeIter<'_> {
581 NodeIter {
582 doc: self,
583 next: self.first_child(id),
584 }
585 }
586
587 pub fn attrs(&self, id: NodeId) -> NodeIter<'_> {
588 NodeIter {
589 doc: self,
590 next: self.first_attr(id),
591 }
592 }
593
594 pub fn len(&self) -> usize {
595 self.nodes.len()
596 }
597}
598
599pub struct NodeIter<'a> {
601 doc: &'a XmlDoc,
602 next: Option<NodeId>,
603}
604
605impl Iterator for NodeIter<'_> {
606 type Item = NodeId;
607
608 fn next(&mut self) -> Option<Self::Item> {
609 let n = self.next?;
610 self.next = self.doc.next_sibling(n);
611 Some(n)
612 }
613}
614
615#[doc(alias = "xmlFreeDoc")]
617pub fn xml_free_doc(_doc: XmlDoc) {}