Skip to main content

kiss_xml/
dom.rs

1/*!
2A document object model (DOM) is a tree data structure with three different kinds of nodes: Element, Text, and Comment nodes. Element nodes can have children (a list of child nodes), while Text and Comment nodes cannot. As per the XML specification, a DOM can only have one root element.
3
4# Examples
5
6## Parse an XML file, modify it, then print it to the terminal
7```rust
8fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
9	use kiss_xml;
10	use kiss_xml::dom::Element;
11	let mut doc = kiss_xml::parse_filepath("tests/some-file.xml")?;
12	doc.root_element_mut().append(Element::new_with_text("note", "note text")?);
13	println!("{}", doc.to_string_with_indent("\t"));
14	Ok(())
15}
16```
17
18## Create a new DOM from scratch
19```rust
20fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
21	use kiss_xml;
22	use kiss_xml::dom::*;
23	use chrono::{DateTime, Utc};
24	let mut doc = Document::new(
25		Element::new_with_children("root", vec![
26			Comment::new(format!("This XML document was generated on {}", Utc::now().to_rfc3339()))?.boxed(),
27			Element::new_with_text("motd", "Message of the day is: hello!")?.boxed()
28		])?
29	);
30	println!("{}", doc.to_string_with_indent("\t"));
31	Ok(())
32}
33```
34
35*/
36
37use std::any::Any;
38use std::cell::OnceCell;
39use std::cmp::Ordering;
40use std::collections::HashMap;
41use std::fmt::Formatter;
42
43use std::hash::{Hash, Hasher};
44use std::path::Path;
45use regex::Regex;
46use crate::errors::*;
47
48/**
49A Document represents a DOM plus additional (optional) metadata such as one or more Document Type Declarations (DTD). Use this struct to write a DOM to a string or file.
50*/
51pub struct Document {
52	/// Optional XML declaration (ie `<?xml version="1.0" encoding="UTF-8"?>`)
53	declaration: Option<Declaration>,
54	/// Doctype defs, if any
55	dtds: Vec<DTD>,
56	/// Root element (multi-element XML docs not supported)
57	root_element: Element
58}
59
60impl Document {
61	/**
62Constructs a new Document with the given root element and default declaration
63	 */
64	pub fn new(root: Element) -> Self {
65		Document::new_with_decl_dtd(root, Some(Declaration::default()), None)
66	}
67	/**
68Full constructor with required root element and optional XML declaration and optional list of one or more document type definition (DTD) items.
69	 */
70	pub fn new_with_decl_dtd(root: Element, declaration: Option<Declaration>, dtd: Option<&[DTD]>) -> Self {
71		Self{
72			declaration: declaration,
73			dtds: match dtd{
74				None => Vec::with_capacity(1),
75				Some(dtds) => Vec::from(dtds)
76			},
77			root_element: root
78		}
79	}
80	/**
81	Returns a list of any and all DTDs for this Document as an iterator
82	 */
83	pub fn doctype_defs(&self) -> impl Iterator<Item = &DTD> {
84		self.dtds.iter()
85	}
86	/**
87	Returns a list of any and all DTDs for this Document as an iterator
88	 */
89	pub fn doctype_defs_mut(&mut self) -> impl Iterator<Item = &mut DTD> {
90		self.dtds.iter_mut()
91	}
92	/**
93Sets the DTDs for this document (a `None` argument will remove all DTDs)
94	 */
95	pub fn set_doctype_defs(&mut self, dtds: Option<&[DTD]>) {
96		match dtds {
97			None => self.dtds = Vec::with_capacity(1),
98			Some(dlist) => self.dtds = Vec::from(dlist)
99		}
100	}
101	/**
102Gets the XML declaration for this document, if it has one (while the XML spec requires a declaration at the start of every XML file, it is commonly omitted, especially when the XML is embedded in a stream or file).
103	 */
104	pub fn declaration(&self) -> &Option<Declaration> {
105		&self.declaration
106	}
107	/**
108Sets the XML declaration for this document (a `None` argument will remove any existing declaration). While the XML spec requires a declaration at the start of every XML file, it is commonly omitted, especially when the XML is embedded in a stream or file.
109	 */
110	pub fn set_declaration(&mut self, decl: Option<Declaration>) {
111		self.declaration = decl
112	}
113
114	/**
115Produces the XML text representing this XML DOM using the default indent of two spaces per level
116	 */
117	pub fn to_string(&self) -> String {
118		self.to_string_with_indent("  ")
119	}
120
121	/**
122	Produces the XML text representing this XML DOM using the provided indent.
123	# Args:
124	 - *indent* - prefix string to use for indenting the output XML. The indent must be either a
125		single tab character or any number of spaces (otherwise a warning will be printed and the
126		default indent used instead)
127	 */
128	pub fn to_string_with_indent(&self, indent: impl Into<String>) -> String {
129		let mut indent = indent.into();
130		match crate::validate_indent(indent.as_str()){
131			Ok(_) => {},
132			Err(_) => {
133				eprintln!("WARNING: {:?} is not a valid indentation. Must be either 1 tab or any number of spaces. The default of 2 spaces will be used instead", indent);
134				indent = "  ".to_string();
135			}
136		};
137		let mut builder = String::new();
138		match &self.declaration{
139			None => {},
140			Some(decl) => {
141				builder.push_str(decl.to_string().as_str());
142				builder.push_str("\n");
143			}
144		}
145		for dtd in &self.dtds {
146			builder.push_str(dtd.to_string().as_str());
147			builder.push_str("\n");
148		}
149		builder.push_str(&self.root_element.to_string_with_indent(indent.as_str()));
150		builder.push_str("\n");
151		return builder;
152	}
153
154	/**
155	Writes this document as XML to the given file using the default indent of two spaces per level, returning a result indicating success or error in this write operation
156	*/
157	pub fn write_to_filepath(&self, path: impl AsRef<Path>) -> std::io::Result<()> {
158		self.write_to_filepath_with_indent(path, "  ")
159	}
160
161	/**
162	Writes this document as XML to the given file using the provided indent, returning a result indicating success or error in this write operation
163	 */
164	pub fn write_to_filepath_with_indent(&self, path: impl AsRef<Path>, indent: impl Into<String>) -> std::io::Result<()> {
165		use std::fs;
166		// if parent dir does not exist, create it
167		match path.as_ref().parent(){
168			None => {}
169			Some(dir) => fs::create_dir_all(dir)?
170		};
171		// write to file
172		fs::write(path, self.to_string_with_indent(indent))
173	}
174
175	/**
176	Writes this document as XML to the given file or stream using the default indent of two spaces per level, returning a result indicating success or error in this write operation
177	 */
178	pub fn write_to_file(&self, out: &mut impl std::io::Write) -> std::io::Result<()> {
179		self.write_to_file_with_indent(out, "  ")
180	}
181
182	/**
183	Writes this document as XML to the given file or stream using the default indent of two spaces per level, returning a result indicating success or error in this write operation
184	 */
185	pub fn write_to_file_with_indent(&self, out: &mut impl std::io::Write, indent: impl Into<String>) -> std::io::Result<()> {
186		write!(out, "{}", self.to_string_with_indent(indent))
187	}
188
189	/**
190	Returns the root element of this DOM as an immutable reference
191	 */
192	pub fn root_element(&self) -> &Element {
193		&self.root_element
194	}
195
196	/**
197	Returns the root element of this DOM as a mutable reference.
198	  */
199	pub fn root_element_mut(&mut self) -> &mut Element {
200		&mut self.root_element
201	}
202}
203
204impl std::fmt::Display for Document{
205	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
206		write!(f, "{}", self.to_string_with_indent("  "))
207	}
208}
209
210impl std::fmt::Debug for Document{
211	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
212		write!(f, "{}", self.to_string_with_indent("  "))
213	}
214}
215
216impl PartialEq<Self> for Document {
217	fn eq(&self, other: &Self) -> bool {
218		self.declaration == other.declaration
219		&& self.dtds == other.dtds
220		&& self.root_element == other.root_element
221	}
222}
223
224/** This enum lists the types of XML DOM nodes used in kiss_xml, useful for runtime reflection. */
225#[derive(PartialEq, Eq, Clone, Copy, Debug)]
226pub enum DomNodeType {
227	/// node type is CDATA
228	CDataNode,
229	/// node type is Comment
230	CommentNode,
231	/// node type is Element
232	ElementNode,
233	/// node type is Text
234	TextNode
235}
236
237impl From<Box<dyn Node>> for DomNodeType {
238	fn from(value: Box<dyn Node>) -> Self {
239		value.node_type()
240	}
241}
242
243impl std::fmt::Display for DomNodeType {
244	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
245		match self {
246			DomNodeType::CDataNode => write!(f, "CDATA"),
247			DomNodeType::CommentNode => write!(f, "Comment"),
248			DomNodeType::ElementNode => write!(f, "Element"),
249			DomNodeType::TextNode => write!(f, "Text"),
250		}
251	}
252}
253
254/**
255A node in the DOM tree. Elements, Comments, and Text are all types of nodes, but only Elements can be branch nodes with children of their own.
256 */
257pub trait Node: dyn_clone::DynClone + std::fmt::Debug + std::fmt::Display + ToString {
258
259	/**
260	Returns the text content of the node. For a Comment, CData, or Text node, this is just the comment or text string. For an Element, this will return *all* text nodes (including from child elements, recursive scan) as a single string, or an empty string if this element has no child text nodes
261	 */
262	fn text(&self) -> String;
263
264	/**
265	Returns `true` if this Node trait object is an Element struct, otherwise `false`
266	 */
267	fn is_element(&self) -> bool;
268
269	/**
270	Returns `true` if this Node trait object is a Text struct, otherwise `false`
271	 */
272	fn is_text(&self) -> bool;
273
274	/**
275	Returns `true` if this Node trait object is a Comment struct, otherwise `false`
276	 */
277	fn is_comment(&self) -> bool;
278
279	/**
280	Returns `true` if this Node trait object is a CData struct, otherwise `false`
281	 */
282	fn is_cdata(&self) -> bool;
283
284	/**
285	Returns the type information for this node
286	*/
287	fn node_type(&self) -> DomNodeType {
288		if self.is_cdata() {
289			DomNodeType::CDataNode
290		} else if self.is_comment() {
291			DomNodeType::CommentNode
292		} else if self.is_element() {
293			DomNodeType::ElementNode
294		} else if self.is_text() {
295			DomNodeType::TextNode
296		} else {
297			panic!("Logic error! Box<dyn Node> value has no corresponding type in enum DomNodeType")
298		}
299	}
300
301	/**
302	Casts this Node to an Element struct (if the Node is not an Element struct, then `Err(TypeCastError)` error result is returned).
303	 */
304	fn as_element(&self) -> Result<&Element, TypeCastError>;
305
306	/**
307	Casts this Node to a Comment struct (if the Node is not an Comment struct, then `Err(TypeCastError)` error result is returned).
308	 */
309	fn as_comment(&self) -> Result<&Comment, TypeCastError>;
310
311	/**
312	Casts this Node to a Text struct (if the Node is not a Text struct, then `Err(TypeCastError)` error result is returned).
313	 */
314	fn as_text(&self) -> Result<&Text, TypeCastError>;
315
316	/**
317	Casts this Node to a CData struct (if the Node is not an CData struct, then `Err(TypeCastError)` error result is returned).
318	 */
319	fn as_cdata(&self) -> Result<&CData, TypeCastError>;
320
321	/**
322	Casts this Node to an Element struct (if the Node is not an Element struct, then `Err(TypeCastError)` error result is returned).
323	 */
324	fn as_element_mut(&mut self) -> Result<&mut Element, TypeCastError>;
325
326	/**
327	Casts this Node to a Comment struct (if the Node is not an Comment struct, then `Err(TypeCastError)` error result is returned).
328	 */
329	fn as_comment_mut(&mut self) -> Result<&mut Comment, TypeCastError>;
330
331	/**
332	Casts this Node to a Text struct (if the Node is not a Text struct, then `Err(TypeCastError)` error result is returned).
333	 */
334	fn as_text_mut(&mut self) -> Result<&mut Text, TypeCastError>;
335
336	/**
337	Casts this Node to a CData struct (if the Node is not an CData struct, then `Err(TypeCastError)` error result is returned).
338	 */
339	fn as_cdata_mut(&mut self) -> Result<&mut CData, TypeCastError>;
340
341	/**
342	Casts this struct to a Node trait object
343	 */
344	fn as_node(&self) -> &dyn Node;
345
346	/**
347	Casts this struct to a Node trait object
348	 */
349	fn as_node_mut(&mut self) -> &mut dyn Node;
350
351	/**
352	Allows for run-time type casting with the `Any` trait
353	 */
354	fn as_any(&self) -> &dyn Any;
355
356	/**
357	Allows for run-time type casting with the `Any` trait
358	 */
359	fn as_any_mut(&mut self) -> &mut dyn Any;
360
361	/**
362	Writes this Node to a string with the provided indent (used to serialize to XML)
363	# Args:
364	 - *indent* - prefix string to use for indenting the output XML. The indent must be either a
365		single tab character or any number of spaces (otherwise a warning will be printed and the
366		default indent used instead)
367	 */
368	fn to_string_with_indent(&self, indent: &str) -> String;
369
370	/** Converts this node into a `Box<dyn Node>` for convenient use in collections */
371	fn boxed(self) -> Box<dyn Node>;
372}
373
374/// clones a given boxed node
375pub fn clone_node(node: &Box<dyn Node>) -> Box<dyn Node> {
376	if node.is_element() {
377		Box::new(node.as_element().expect("logic error").clone())
378	} else if node.is_text() {
379		Box::new(node.as_text().expect("logic error").clone())
380	} else if node.is_comment() {
381		Box::new(node.as_comment().expect("logic error").clone())
382	} else if node.is_cdata() {
383		Box::new(node.as_cdata().expect("logic error").clone())
384	} else {
385		panic!("logic error: Node is neither of Element, Text, Comment, nor CData");
386	}
387}
388
389/// Returns true if the two nodes are equal, false otherwise
390pub fn node_eq(n1: &Box<dyn Node>, n2: &Box<dyn Node>) -> bool {
391	let t1 = n1.node_type();
392	let t2 = n2.node_type();
393	if t1 != t2 {
394		return false;
395	}
396	return match t1 {
397		DomNodeType::CDataNode =>
398			n1.as_cdata().unwrap() == n2.as_cdata().unwrap(),
399		DomNodeType::CommentNode =>
400			n1.as_comment().unwrap() == n2.as_comment().unwrap(),
401		DomNodeType::ElementNode =>
402			n1.as_element().unwrap() == n2.as_element().unwrap(),
403		DomNodeType::TextNode =>
404			n1.as_text().unwrap() == n2.as_text().unwrap()
405	}
406}
407
408/// Represents an XML element with a name, text content, attributes, xmlns namespace (with optional prefix), and children.
409pub struct Element {
410	/// Name of this element
411	name: String,
412	/// All child nodes
413	child_nodes: Vec<Box<dyn Node>>,
414	/// This element's attributes
415	attributes: HashMap<String, String>,
416	/// optional xmlns (if xmlns_prefix is None then this is default namespace)
417	xmlns: Option<String>,
418	/// optional xmlns (if xmlns_prefix is None then the xmlns is default namespace)
419	xmlns_prefix: Option<String>,
420	/// xmlns definitions for this element, if any
421	xmlns_context: HashMap<String, String>
422}
423
424impl Element {
425	/**
426	Creates a new Element
427	# Args:
428	* *name*: Element name for this XML element (ie "body" for `<body>some text</body>`)
429	* *text*: Optional text content for this element (ie "some text" for `<body>some text</body>`)
430	* *attributes*: optional HashMap of attributes
431	* *xmlns*: optional namespace for this element. Note that this will override any xmlns definitions in the attributes
432	* *xmlns_prefix*: optional namespace prefix. If `xmlns` is not `None` but `xmlns_prefix` is `None`, then this element will set it's xmlns as the default xlmns for it and its children. Note that this will override any xmlns definitions in the attributes
433	* *children*: optional list of child nodes to add to this element
434	 */
435	pub fn new<TEXT1: Into<String>+Clone, TEXT2: Into<String>+Clone>(
436		name: impl Into<String>, text: Option<String>,
437		attributes: Option<HashMap<TEXT1, TEXT2>>,
438		xmlns: Option<String>,
439		xmlns_prefix: Option<String>,
440		children: Option<Vec<Box<dyn Node>>>
441	) -> Result<Self, KissXmlError> {
442		// sanity check
443		let name = name.into();
444		Element::check_elem_name(name.as_str())?;
445		// first, convert attributes to <String,String> map
446		let mut attrs: HashMap<String, String> = HashMap::new();
447		match attributes {
448			None => {}
449			Some(attr_map) => {
450				for (k, v) in attr_map.iter() {
451					let n: String = k.clone().into();
452					Element::check_attr_name(n.as_str())?;
453					attrs.insert(n, v.clone().into());
454				}
455			}
456		}
457		// xmlns check
458		let mut xmlns = xmlns;
459		if xmlns.is_none() {
460			match &xmlns_prefix {
461				None => {
462					// default xmlns
463					xmlns = match attrs.get("xmlns"){
464						None => None,
465						Some(ns) => Some(ns.to_string())
466					}
467				},
468				Some(prefix) => {
469					// prefixed xmlns
470					xmlns = match attrs.get(&format!("xmlns:{prefix}")){
471						None => None,
472						Some(ns) => Some(ns.to_string())
473					}
474				}
475			};
476		}
477		// set the XML NS from the attributes and provided args
478		let mut elem = Self {
479			name: name,
480			child_nodes: Vec::new(),
481			xmlns_context: Element::xmlns_context_from_attributes(&attrs),
482			attributes: attrs,
483			xmlns: xmlns.map(|s| s.to_string()),
484			xmlns_prefix: xmlns_prefix.map(|s| s.to_string())
485		};
486		// finally, add children
487		// (using the append*(...) functions in case of default namespace inheritance)
488		match text {
489			None => {}
490			Some(t) => elem.append(Text::new(t))
491		}
492		match children {
493			None => {},
494			Some(child_vec) => elem.append_all(child_vec)
495		};
496		return Ok(elem);
497	}
498	/// Creates a new Element with the specified name and not attributes or content.
499	pub fn new_from_name(name: &str) -> Result<Self, KissXmlError> {
500		// sanity check
501		Element::check_elem_name(name)?;
502		Ok(Self {
503			name: name.to_string(),
504			..Default::default()
505		})
506	}
507	/** Creates a new Element with the specified name and attributes.
508	# Example
509	```rust
510	fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
511		use kiss_xml::dom::*;
512		use std::collections::HashMap;
513		let e = Element::new_with_attributes("b", HashMap::from([
514			("style", "color: blue")
515		]))?;
516		println!("{}", e); // prints `<b style="color: blue"/>`
517		Ok(())
518	}
519	```
520	 */
521	pub fn new_with_attributes<TEXT1: Into<String>+Clone, TEXT2: Into<String>+Clone>(name: &str, attributes: HashMap<TEXT1, TEXT2>) -> Result<Self, KissXmlError> {
522		Self::new(name, None, Some(attributes), None, None, None)
523	}
524	/// Creates a new Element with the specified name and text content
525	pub fn new_with_text(name: &str, text: impl Into<String>) -> Result<Self, KissXmlError> {
526		Self::new(name, Some(text.into()), Option::<HashMap<String,String>>::None, None, None, None)
527	}
528	/** Creates a new Element with the specified name, attributes, and text.
529	# Example
530	```rust
531	fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
532		use kiss_xml::dom::*;
533		use std::collections::HashMap;
534		let e = Element::new_with_attributes_and_text(
535			"b",
536			HashMap::from([
537				("style", "color: blue")
538			]),
539			"goose"
540		)?;
541		println!("{}", e); // prints `<b style="color: blue">goose</b>`
542		Ok(())
543	}
544	```
545	 */
546	pub fn new_with_attributes_and_text<TEXT1: Into<String>+Clone, TEXT2: Into<String>+Clone>(name: &str, attributes: HashMap<TEXT1, TEXT2>, text: impl Into<String>) -> Result<Self, KissXmlError> {
547		Self::new(name, Some(text.into()), Some(attributes), None, None, None)
548	}
549	/**
550	Creates a new Element with the specified name, attributes, and children.
551	# Example
552	```rust
553	fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
554		use kiss_xml::dom::*;
555		use std::collections::HashMap;
556		let e = Element::new_with_attributes_and_children(
557			"contact",
558			HashMap::from([
559				("id", "123")
560			]),
561			vec![Element::new_with_text("name", "Billy Bob")?.boxed()]
562		)?;
563		println!("{}", e);
564		/* prints:
565			<contact id="123">
566				<name>Billy Bob</name>
567			</contact>
568		*/
569		Ok(())
570	}
571	```
572	 */
573	pub fn new_with_attributes_and_children<TEXT1: Into<String>+Clone, TEXT2: Into<String>+Clone>(name: &str, attributes: HashMap<TEXT1, TEXT2>, children: Vec<Box<dyn Node>>) -> Result<Self, KissXmlError> {
574		Self::new(name, None, Some(attributes), None, None, Some(children))
575	}
576
577	/**
578	Creates a new Element with the specified name and children.
579	# Example
580	```rust
581	fn main() -> Result<(), kiss_xml::errors::KissXmlError> {
582		use kiss_xml::dom::*;
583		use std::collections::HashMap;
584		let e = Element::new_with_children(
585			"contact",
586			vec![Element::new_with_text("name", "Billy Bob")?.boxed()]
587		)?;
588		println!("{}", e);
589		/* prints:
590			<contact>
591				<name>Billy Bob</name>
592			</contact>
593		*/
594		Ok(())
595	}
596	```
597	 */
598	pub fn new_with_children(name: &str, children: Vec<Box<dyn Node>>) -> Result<Self, KissXmlError> {
599		Self::new(name, None, Option::<HashMap<String,String>>::None, None, None, Some(children))
600	}
601	/** checks the element's attributes for xmlns definitions
602	Note that the default xmlns (if present) is saved as prefix ""
603	# Args
604	* attrs - kay=value pairs for the element
605	 */
606	fn xmlns_context_from_attributes(attrs: &HashMap<String, String>) -> HashMap<String, String> {
607		// then parse xmlns prefixes
608		let mut prefixes: HashMap<String, String> = HashMap::new();
609		for (k, v) in attrs.iter() {
610			let key = k.as_str();
611			if key.starts_with("xmlns:") {
612				let split: Vec<&str> = key.splitn(2, ":").collect();
613				let prefix = split[1].to_string();
614				let ns = v.clone();
615				prefixes.insert(prefix, ns);
616			}
617		}
618		return prefixes;
619	}
620	/** Returns the tag name of this element (eg "book" for element `<book />`) */
621	pub fn name(&self) -> String {
622		self.name.clone()
623	}
624	/**
625	Returns the namespace of this element, or `None` if it does not have a namespace. If this element has a namespace but `namespace_prefix()` returns `None`, then the namespace is a default namespace (no prefix, can be inherited by children).
626	 */
627	pub fn namespace(&self) -> Option<String> {
628		self.xmlns.clone()
629	}
630	/**
631	Returns the default namespace of this element, or `None` if it does not have a default namespace. Default namespaces do not use prefixes and are inherited by the element's children.
632	 */
633	pub fn default_namespace(&self) -> Option<String> {
634		match self.xmlns_prefix{
635			None => self.xmlns.clone(),
636			Some(_) => None
637		}
638	}
639	/**
640	This is the tag name as it will appear in serialized XML. If this element has an xmlns prefix, then this returns prefix:name, otherwise it just returns the name
641	*/
642	pub fn tag_name(&self) -> String {
643		match &self.xmlns_prefix{
644			None => self.name.clone(),
645			Some(prefix) => format!("{}:{}", prefix, self.name)
646		}
647	}
648	/**
649	Returns the prefix of this element's namespace, if it has a prefixed namespace. If this element has a namespace but `namespace_prefix()` returns `None`, then the namespace is a default namespace (no prefix, can be inherited by children).
650	 */
651	pub fn namespace_prefix(&self) -> Option<String> {
652		self.xmlns_prefix.clone()
653	}
654
655	/**
656	Returns a list (as an iterator) of all child elements that belong to the given XML namespace. This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements(...)](search_elements()) instead.
657
658	To get a list of elements that have no XML namespace associated with them, pass `None` as the argument to this function.
659	# Example
660	```rust
661	fn main() -> Result<(), Box<dyn std::error::Error>> {
662		use std::str::FromStr;
663		use kiss_xml;
664		use kiss_xml::dom::*;
665		let doc = kiss_xml::parse_str(r#"<?xml version="1.0" encoding="UTF-8"?>
666	<root xmlns:img="internal://ns/a" xmlns:dim="internal://ns/b">
667		<width>200</width>
668		<height>150</height>
669		<depth>50</depth>
670		<img:width>200</img:width>
671		<img:height>150</img:height>
672		<dim:width>200</dim:width>
673	</root>"#)?;
674		for e in doc.root_element().elements_by_namespace(Some(&String::from_str("internal://ns/a")?)){
675			println!("img element <{}> contains {:?}", e.name(), e.text())
676		}
677		/* Prints:
678		img element <width> contains '200'
679		img element <height> contains '150'
680		*/
681		Ok(())
682	}
683	```
684	 */
685	pub fn elements_by_namespace(&self, namespace: Option<&str>) -> impl Iterator<Item = &Element>{
686		let ns = namespace.map(|s| s.to_string());
687		self.child_elements().filter(move |c| c.xmlns == ns)
688	}
689	/** Returns a list (as an iterator) of all child elements that belong to the given XML namespace. This search is non-recursive, meaning that it only returns children of this element, not children-of-children.
690
691	To get a list of elements that have no XML namespace associated with them, pass `None` as the argument to this function.
692	# Example
693	```rust
694	fn main() -> Result<(), Box<dyn std::error::Error>> {
695		use std::str::FromStr;
696		use kiss_xml;
697		use kiss_xml::dom::*;
698		let mut doc = kiss_xml::parse_str(r#"<?xml version="1.0" encoding="UTF-8"?>
699	<root xmlns:img="internal://ns/a" xmlns:dim="internal://ns/b">
700		<width>200</width>
701		<height>150</height>
702		<depth>50</depth>
703		<img:width>200</img:width>
704		<img:height>150</img:height>
705		<dim:width>200</dim:width>
706	</root>"#)?;
707		for e in doc.root_element_mut().elements_by_namespace_mut(Some("internal://ns/a")){
708			e.set_text("0");
709		}
710		for e in doc.root_element().elements_by_namespace(Some("internal://ns/a")){
711			println!("img element <{}> contains {:?}", e.name(), e.text())
712		}
713		/* Prints:
714		img element <width> contains '0'
715		img element <height> contains '0'
716		*/
717		Ok(())
718	}
719	```
720	 */
721	pub fn elements_by_namespace_mut(&mut self, namespace: Option<&str>) -> impl Iterator<Item = &mut Element>{
722		let ns = namespace.map(|s| s.to_string());
723		self.child_elements_mut().filter(move |c| c.xmlns == ns)
724	}
725	/**
726	Returns a list (as an iterator) of all child elements that belong to the given XML namespace according to the namespace's prefix (eg `<svg:g xmlns:svg="http://www.w3.org/2000/svg">`). This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements(...)](search_elements()) instead.
727
728	To get a list of elements that have no xmlns prefix associated with them, pass `None` as the argument to this function (this will still return elements with a default namespace as well as elements with no namespace).
729	# Example
730	```rust
731	fn main() -> Result<(), Box<dyn std::error::Error>> {
732		use std::str::FromStr;
733		use kiss_xml;
734		use kiss_xml::dom::*;
735		let doc = kiss_xml::parse_str(r#"<?xml version="1.0" encoding="UTF-8"?>
736	<root xmlns:img="internal://ns/a" xmlns:dim="internal://ns/b">
737		<width>200</width>
738		<height>150</height>
739		<depth>50</depth>
740		<img:width>200</img:width>
741		<img:height>150</img:height>
742		<dim:width>200</dim:width>
743	</root>"#)?;
744		for e in doc.root_element().elements_by_namespace_prefix(Some("img")){
745			println!("img element <{}> contains {:?}", e.name(), e.text())
746		}
747		/* Prints:
748		img element <width> contains '200'
749		img element <height> contains '150'
750		*/
751		Ok(())
752	}
753	 */
754	pub fn elements_by_namespace_prefix(&self, prefix: Option<&str>) ->  impl Iterator<Item = &Element>{
755		let pfx = prefix.map(|p| p.to_string());
756		self.child_elements().filter(move |c| c.xmlns_prefix == pfx)
757	}
758	/**
759	Returns a list (as an iterator) of all child elements that belong to the given XML namespace according to the namespace's prefix (eg `<svg:g xmlns:svg="http://www.w3.org/2000/svg">`). This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements(...)](search_elements()) instead.
760
761	To get a list of elements that have no xmlns prefix associated with them, pass `None` as the argument to this function (this will still return elements with a default namespace as well as elements with no namespace).
762	# Example
763	```rust
764	fn main() -> Result<(), Box<dyn std::error::Error>> {
765		use std::str::FromStr;
766		use kiss_xml;
767		use kiss_xml::dom::*;
768		let mut doc = kiss_xml::parse_str(r#"<?xml version="1.0" encoding="UTF-8"?>
769	<root xmlns:img="internal://ns/a" xmlns:dim="internal://ns/b">
770		<width>200</width>
771		<height>150</height>
772		<depth>50</depth>
773		<img:width>200</img:width>
774		<img:height>150</img:height>
775		<dim:width>200</dim:width>
776	</root>"#)?;
777		for e in doc.root_element_mut().elements_by_namespace_prefix_mut(Some("img")){
778			e.set_text("-1")
779		}
780		for e in doc.root_element().elements_by_namespace_prefix(Some("img")){
781			println!("img element <{}> contains {:?}", e.name(), e.text())
782		}
783		/* Prints:
784		img element <width> contains '-1'
785		img element <height> contains '-1'
786		*/
787		Ok(())
788	}
789	 */
790	pub fn elements_by_namespace_prefix_mut(&mut self, prefix: Option<&str>) ->  impl Iterator<Item = &mut Element>{
791		let pfx = prefix.map(|p| p.to_string());
792		self.child_elements_mut().filter(move |c| c.xmlns_prefix == pfx)
793	}
794	/** Gets any and all xmlns prefixes defined in this element (does not include prefix-less default namespace, nor prefixes inherited from a parent element) */
795	pub fn namespace_prefixes(&self) -> Option<HashMap<String, String>> {
796		let prefixes = Self::xmlns_context_from_attributes(&self.attributes);
797		if prefixes.is_empty() {
798			None
799		} else {
800			Some(prefixes)
801		}
802	}
803	/** Gets any and all xmlns prefixes relevant to this element. This includes both those that are defined by this element as well as those defined by parent elements up the DOM tree. */
804	pub(crate) fn get_namespace_context(&self) -> HashMap<String, String> {self.xmlns_context.clone()}
805	/** Sets any and all xmlns prefixes this element should inherit. This must include both those that are defined by this element as well as those defined by parent elements up the DOM tree. */
806	pub(crate) fn set_namespace_context(&mut self, parent_default_namespace: Option<String>, parent_prefixes: Option<HashMap<String, String>>) {
807		// inherit default namespace unless this element also defines one
808		match self.xmlns_prefix {
809			None => {
810				match self.default_namespace() {
811					None => self.xmlns = parent_default_namespace,
812					Some(_) => {/* do nothing */}
813				}
814			}
815			Some(_) => {/* do nothing */}
816		}
817		// add prefixed namespaces (except where already defined locally)
818		match parent_prefixes {
819			None => {}
820			Some(prefixes) => {
821				for (prefix, ns) in prefixes {
822					if ! self.xmlns_context.contains_key(prefix.as_str()) {
823						let _ = &self.xmlns_context.insert(prefix, ns);
824					}
825				}
826			}
827		}
828		// set this namespace if a prefix was specified without xmlns def attribute
829		if self.xmlns.is_none() {
830			match &self.xmlns_prefix {
831				None => {}
832				Some(prefix) => {
833					// get prefix namespace from context
834					self.xmlns = self.xmlns_context.get(prefix).map(String::clone);
835				}
836			};
837		}
838	}
839	/** flips the order of child nodes (non-recursive) */
840	pub(crate) fn reverse_children(&mut self) {
841		self.child_nodes.reverse();
842	}
843	/** Returns a list of al child elements as an iterator */
844	pub fn child_elements(&self) ->  impl Iterator<Item = &Element>{
845		self.child_nodes.iter()
846			.filter(|n| n.is_element())
847			.map(|n| n.as_element().expect("logic error"))
848	}
849	/** Returns a list of al child elements as an iterator */
850	pub fn child_elements_mut(&mut self) ->  impl Iterator<Item = &mut Element>{
851		self.child_nodes.iter_mut()
852			.filter(|n| n.is_element())
853			.map(|n| n.as_element_mut().expect("logic error"))
854	}
855	/** Returns a list of al child nodes (elements, comments, and text components) as an iterator (non-recursive). For a recursive iterator of all children and children-of-children, use [all_children()](all_children())*/
856	pub fn children(&self) -> impl Iterator<Item = &Box<dyn Node>>{
857		self.child_nodes.iter()
858	}
859	/** Returns a recusive iterator to all child nodes (elements, comments, and text components) */
860	pub fn all_children(&self) -> impl Iterator<Item = &Box<dyn Node>>{
861		self.search(|_| true)
862	}
863	/** Returns a list of al child nodes (elements, comments, and text components) as an iterator */
864	pub fn children_mut(&mut self) -> impl Iterator<Item = &mut Box<dyn Node>>{
865		self.child_nodes.iter_mut()
866	}
867	/** Recursively iterates through all child nodes, as well as children of children. Iteration order is arbitrary and not sequential through the DOM. */
868	pub fn children_recursive(&self) -> Box<dyn Iterator<Item = &Box<dyn Node>> + '_> {
869		Box::new(
870			self.child_nodes.iter()
871			.chain(
872				self.child_elements().map(|e| e.children_recursive()
873				).flatten()
874			)
875		)
876	}
877
878	/** Deletes all child nodes from this element */
879	pub fn clear_children(&mut self) {self.child_nodes.clear()}
880	/** Replaces this element's content (children) with the given text. **This will delete any child elements and comments from this element!** */
881	pub fn set_text(&mut self, text: impl Into<String>) {
882		self.clear_children();
883		self.append(Text::new(text));
884	}
885	/**
886	Gets the first child element with the given element name. If no such element exists, an error result is returned.
887
888	This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements(...)](search_elements()) instead.
889	# Example
890	```rust
891	fn main() -> Result<(), Box<dyn std::error::Error>> {
892		use kiss_xml;
893		use kiss_xml::errors::DoesNotExistError;
894		let doc = kiss_xml::parse_str(r#"<body>
895		<p>Hello there!</p>
896		<p>Good-bye!</p>
897	</body>"#)?;
898		println!("1st <p>: {}",
899			doc.root_element()
900			.first_element_by_name("p")?
901		);
902		// prints: "1st <p>: Hello there!"
903		Ok(())
904	}
905	```
906	 */
907	pub fn first_element_by_name(&self, name: impl Into<String>) -> Result<&Element, DoesNotExistError> {
908		let n: String = name.into();
909		for e in self.child_elements() {
910			if e.name() == n {
911				return Ok(e);
912			}
913		}
914		Err(DoesNotExistError::default())
915	}
916	/**
917	Gets the first child element with the given element name as a mutable reference. If no such element exists, an error result is returned.
918
919	This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements(...)](search_elements()) instead.
920	# Example
921	```rust
922	fn main() -> Result<(), Box<dyn std::error::Error>> {
923		use kiss_xml;
924		use kiss_xml::errors::DoesNotExistError;
925		let mut doc = kiss_xml::parse_str(r#"<body>
926		<p>Hello there!</p>
927	</body>"#)?;
928		doc.root_element_mut()
929			.first_element_by_name_mut("p")?
930			.set_text("Good bye!");
931		Ok(())
932	}
933	```
934	 */
935	pub fn first_element_by_name_mut(&mut self, name: impl Into<String>) -> Result<&mut Element, DoesNotExistError> {
936		let n: String = name.into();
937		for e in self.child_elements_mut() {
938			if e.name() == n {
939				return Ok(e);
940			}
941		}
942		Err(DoesNotExistError::default())
943	}
944	/** Returns a list of all child elements with the given name as an iterator.
945
946	This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements_by_name(...)](search_elements_by_name()) instead.
947	 */
948	pub fn elements_by_name(&self, name: impl Into<String>) ->  impl Iterator<Item = &Element>{
949		let n: String = name.into();
950		self.child_elements().filter(move |c| c.name == n)
951	}
952	/** Returns a list of all child elements with the given name as an iterator.
953
954	This search is non-recursive, meaning that it only returns children of this element, not children-of-children. For a recursive search, use [search_elements_by_name(...)](search_elements_by_name()) instead.
955	 */
956	pub fn elements_by_name_mut(&mut self, name: impl Into<String>) ->  impl Iterator<Item = &mut Element>{
957		let n: String = name.into();
958		self.child_elements_mut().filter(move |c| c.name == n)
959	}
960	/** Gets the attributes for this element as a `HashMap` */
961	pub fn attributes(&self) -> &HashMap<String, String> {
962		&self.attributes
963	}
964	/** Gets the value of an attribute for this Element by name. If there is no such attribute, `None` is returned */
965	pub fn get_attr(&self, attr_name: impl Into<String>) -> Option<&String> {
966		let n: String = attr_name.into();
967		self.attributes.get(&n)
968	}
969	/** Sets the value of an attribute for this Element by name. */
970	pub fn set_attr(&mut self, attr_name: impl Into<String>, value: impl Into<String>) -> Result<(), InvalidAttributeName> {
971		let n: String = attr_name.into();
972		Element::check_attr_name(n.as_str())?;
973		let v: String = value.into();
974		self.attributes.insert(n, v);
975		Ok(())
976	}
977
978
979	/// singleton regex matcher
980	const ATTR_NAME_CHECKER_SINGLETON: OnceCell<Regex> = OnceCell::new();
981	/// Checks if an attribute name is valid
982	fn check_attr_name(name: &str) -> Result<(), InvalidAttributeName> {
983		let singleton = Element::ATTR_NAME_CHECKER_SINGLETON;
984		let checker = singleton.get_or_init(
985			|| Regex::new(r#"^[_a-zA-Z]\S*$"#).unwrap()
986		);
987		if checker.is_match(name) {
988			Ok(())
989		} else {
990			Err(InvalidAttributeName::new(format!("'{}' is not a valid attribute name", name)))
991		}
992	}
993	/// singleton regex matcher
994	const NAME_CHECKER_SINGLETON: OnceCell<Regex> = OnceCell::new();
995	/// Checks if an attribute name is valid
996	fn check_elem_name(name: &str) -> Result<(), InvalidElementName> {
997		let singleton = Element::NAME_CHECKER_SINGLETON;
998		let checker = singleton.get_or_init(
999			|| Regex::new(r#"^[_a-zA-Z]\S*$"#).unwrap()
1000		);
1001		if checker.is_match(name) {
1002			Ok(())
1003		} else {
1004			Err(InvalidElementName::new(format!("'{}' is not a valid name", name)))
1005		}
1006	}
1007	/** Deletes an attribute from this element */
1008	pub fn remove_attr(&mut self, attr_name: impl Into<String>) -> Option<String> {
1009		let n: String = attr_name.into();
1010		self.attributes.remove(&n)
1011	}
1012	/** Deletes all attributes from this element */
1013	pub fn clear_attributes(&mut self) {
1014		self.attributes.clear()
1015	}
1016	/**
1017	Performs a recursive search of all child nodes of this element (and all children of child elements, etc), returning an iterator of all nodes matching the given predicate.
1018
1019	# Example
1020	```rust
1021	fn main() -> Result<(), Box<dyn std::error::Error>> {
1022		use kiss_xml;
1023		use kiss_xml::dom::*;
1024		let library = kiss_xml::parse_str(r#"<root>
1025			<books>
1026				<asian>
1027					<book genre="fantasy" count="1">Journey to the West</book>
1028				</asian>
1029				<european>
1030					<book genre="fantasy" count="1">The Lord of the Rings</book>
1031					<book genre="sci-fi" count="1">The Hitchhiker's Guide to the Galaxy</book>
1032				</european>
1033			</books>
1034		</root>"#)?;
1035		println!("Fantasy books:");
1036		for fantasy_book in library.root_element().search(
1037			|n| n.is_element() && n.as_element().unwrap().get_attr("genre") == Some(&"fantasy".to_string())
1038		){
1039			println!("{}", fantasy_book.text());
1040		}
1041		Ok(())
1042	}
1043	```
1044	 */
1045	pub fn search<'a, P>(&'a self, predicate: P) -> Box<dyn Iterator<Item = &'a Box<dyn Node>> + 'a> where P: FnMut(&&Box<dyn Node>) -> bool + 'a {
1046		// recursive
1047		Box::new(
1048			self.children_recursive().filter(predicate)
1049		)
1050	}
1051	/**
1052	Performs a recursive search of all child elements (and all children of child elements, etc), returning an iterator of all elements matching the given predicate.
1053
1054	# Example
1055	```rust
1056	fn main() -> Result<(), Box<dyn std::error::Error>> {
1057		use kiss_xml;
1058		use kiss_xml::dom::*;
1059		let library = kiss_xml::parse_str(r#"<root>
1060			<books>
1061				<asian>
1062					<book genre="fantasy" count="1">Journey to the West</book>
1063				</asian>
1064				<european>
1065					<book genre="fantasy" count="1">The Lord of the Rings</book>
1066					<book genre="sci-fi" count="1">The Hitchhiker's Guide to the Galaxy</book>
1067				</european>
1068			</books>
1069		</root>"#)?;
1070		println!("Fantasy books:");
1071		for fantasy_book in library.root_element().search_elements(
1072			|e| e.get_attr("genre") == Some(&String::from("fantasy"))
1073		){
1074			println!("{}", fantasy_book.text());
1075		}
1076		Ok(())
1077	}
1078	```
1079	 */
1080	pub fn search_elements<'a, P>(&'a self, predicate: P) ->  Box<dyn Iterator<Item = &'a Element> + 'a> where P: FnMut(&&Element) -> bool + 'a {
1081		// recursive
1082		Box::new(
1083			self.search(|n| n.is_element())
1084				.map(|n| n.as_element().expect("logic error"))
1085				.filter(predicate)
1086		)
1087	}
1088	/**
1089	Performs a recursive search of all child elements (and all children of child elements, etc), returning an iterator of all elements with the given name (regardless of namespace).
1090
1091	# Example
1092	```rust
1093	fn main() -> Result<(), Box<dyn std::error::Error>> {
1094		use kiss_xml;
1095		use kiss_xml::dom::*;
1096		let library = kiss_xml::parse_str(r#"<root>
1097			<books>
1098				<asian>
1099					<book genre="fantasy" count="1">Journey to the West</book>
1100				</asian>
1101				<european>
1102					<book genre="fantasy" count="1">The Lord of the Rings</book>
1103					<book genre="sci-fi" count="1">The Hitchhiker's Guide to the Galaxy</book>
1104				</european>
1105			</books>
1106		</root>"#)?;
1107		println!("All books:");
1108		for book in library.root_element().search_elements_by_name(
1109			"book"
1110		){
1111			println!("{}", book.text());
1112		}
1113		Ok(())
1114	}
1115	```
1116 	*/
1117	pub fn search_elements_by_name(&self, name: impl Into<String>) ->  impl Iterator<Item = &Element>{
1118		// recursive
1119		let n: String = name.into();
1120		self.search_elements(move |e| e.name() == n)
1121	}
1122	/** Performs a recursive search of all the text nodes under this element and returns all text nodes that match the given predicate as an iterator */
1123	pub fn search_text<'a, P>(&'a self, predicate: P) -> Box<dyn Iterator<Item = &'a Text> + 'a> where P: Fn(&&Text) -> bool + 'a {
1124		// recursive
1125		Box::new(
1126			self.search(|n| n.is_text())
1127			.map(|n| n.as_text().expect("logic error"))
1128			.filter(predicate)
1129		)
1130	}
1131
1132	/** Performs a recursive search of all the comments under this element and returns all comment nodes that match the given predicate as an iterator */
1133	pub fn search_comments<'a, P>(&'a self, predicate: P) -> Box<dyn Iterator<Item = &'a Comment> + 'a> where P: Fn(&&Comment) -> bool + 'a {
1134		// recursive
1135		Box::new(
1136			self.search(|n| n.is_comment())
1137				.map(|n| n.as_comment().expect("logic error"))
1138				.filter(predicate)
1139		)
1140	}
1141	/**
1142	Appends the given node to the children of this element.
1143
1144	# Example
1145	```rust
1146	fn main() -> Result<(), Box<dyn std::error::Error>> {
1147		use kiss_xml;
1148		use kiss_xml::dom::*;
1149		let mut doc = Document::new(Element::new_from_name("album")?);
1150		doc.root_element_mut().append(Element::new_with_text("song", "I Believe I Can Fly")?);
1151		println!("{}", doc);
1152		/* prints:
1153			<?xml version="1.0" encoding="UTF-8"?>
1154			<album>
1155				<song>I Believe I Can Fly</song>
1156			</album>
1157		*/
1158		Ok(())
1159	}
1160	```
1161	 */
1162	pub fn append(&mut self, node: impl Node) {
1163		// Note: if this is an element, set the namespace context
1164		self.append_boxed(node.boxed());
1165	}
1166	/** same as [append(...)](Element::append()) but for a Box&lt;dyn Node&gt; */
1167	pub fn append_boxed(&mut self, mut node: Box<dyn Node>) {
1168		Self::apply_xmlns_context_to_child_node(self.default_namespace(), self.xmlns_context.clone(), &mut node);
1169		self.child_nodes.push(node);
1170		// clean-up text nodes
1171		self.cleanup_text_nodes();
1172	}
1173	/** Applies this element's context to the given child */
1174	fn apply_xmlns_context_to_child_node(df_xmlns: Option<String>, xmlns_context: HashMap<String, String>, node: &mut Box<dyn Node>) {
1175		let is_element = node.is_element();
1176		if is_element {
1177			Self::apply_xmlns_context_to_child_element(
1178				df_xmlns, xmlns_context,
1179				node.as_element_mut().expect("logic error")
1180			);
1181		}
1182	}
1183	/** Applies the default xmlns and prefixed xmlns context to the given child */
1184	fn apply_xmlns_context_to_child_element(df_xmlns: Option<String>, xmlns_context: HashMap<String, String>, child: &mut Element) {
1185		// update xmlns prefix context if we just added an element
1186		child.set_namespace_context(
1187			df_xmlns,
1188			Some(xmlns_context)
1189		);
1190	}
1191	/** Discards merges sequential text nodes and then whitespace-only text nodes */
1192	fn cleanup_text_nodes(&mut self) {
1193		// check if there are children
1194		if self.child_nodes.len() == 0 {return;}
1195		// merge sequential text nodes (back-to-front order for performance)
1196		let mut index = self.child_nodes.len() - 1;
1197		while index > 0 {
1198			if self.child_nodes[index].is_text()
1199			&& self.child_nodes[index-1].is_text() {
1200				// index-1 and index are text nodes, merge them
1201				let back = self.child_nodes.remove(index);
1202				let front = self.child_nodes.remove(index-1);
1203				let merged = Text::concat(front.as_text().expect("logic error"), back.as_text().expect("logic error"));
1204				self.child_nodes.insert(index-1, merged.boxed());
1205			}
1206			index -= 1;
1207		}
1208		// remove text nodes that are whitespace
1209		assert!(self.child_nodes.len() > 0, "logic error: self.child_nodes should never be empty here!");
1210		let mut index = self.child_nodes.len() - 1;
1211		loop {
1212			if self.child_nodes[index].is_text()
1213				&& self.child_nodes[index]
1214				.as_text().expect("logic error").is_whitespace() {
1215				self.child_nodes.remove(index);
1216			}
1217			if index == 0 {break;}
1218			index = index.wrapping_sub(1);
1219		}
1220		// Done.
1221	}
1222	/**
1223	Appends multiple child nodes to the current element.
1224
1225	# Example
1226	```rust
1227	fn main() -> Result<(), Box<dyn std::error::Error>> {
1228		use kiss_xml;
1229		use kiss_xml::dom::*;
1230		let mut doc = Document::new(Element::new_from_name("album")?);
1231		doc.root_element_mut().append_all(vec![
1232			Element::new_with_text("song", "I Believe I Can Fly")?.boxed(),
1233			Element::new_with_text("song", "My Heart Will Go On")?.boxed(),
1234			Comment::new("album list incomplete")?.boxed(),
1235		]);
1236		println!("{}", doc);
1237		/* prints:
1238			<?xml version="1.0" encoding="UTF-8"?>
1239			<album>
1240				<song>I Believe I Can Fly</song>
1241				<song>My Heart Will Go On</song>
1242				<!--album list incomplete-->
1243			</album>
1244		*/
1245		Ok(())
1246	}
1247	```
1248	 */
1249	pub fn append_all(&mut self, children: Vec<Box<dyn Node>>) {
1250		// first add every node, keeping a record of which ones were elements
1251		let mut elem_indices: Vec<usize> = Vec::with_capacity(children.len());
1252		let mut i = self.child_nodes.len();
1253		for child in children {
1254			if child.is_element() {
1255				elem_indices.push(i);
1256			}
1257			self.child_nodes.push(child);
1258			i += 1;
1259		}
1260		// then apply the xmlns context to the elements
1261		for i in elem_indices {
1262			Self::apply_xmlns_context_to_child_node(
1263				self.default_namespace(), self.xmlns_context.clone(),
1264			&mut self.child_nodes[i]
1265			);
1266		}
1267		// clean-up text nodes
1268		self.cleanup_text_nodes();
1269	}
1270	/**
1271	Inserts the given node at the given index in this element's list of child nodes (see the `children()` method). If the index is invalid, an error result is returned.
1272	 */
1273	pub fn insert(&mut self, index: usize, node: impl Node) -> Result<(), IndexOutOfBounds> {
1274		if index > self.child_nodes.len() {
1275			return Err(IndexOutOfBounds::new(index as isize, Some((0, self.child_nodes.len() as isize))));
1276		}
1277		// Note: if this is an element, set the namespace context
1278		self.child_nodes.insert(index, node.boxed());
1279		Self::apply_xmlns_context_to_child_node(
1280			self.default_namespace(), self.xmlns_context.clone(),
1281			self.child_nodes.last_mut().unwrap()
1282		);
1283		// clean-up text nodes
1284		self.cleanup_text_nodes();
1285		// done
1286		Ok(())
1287	}
1288	/**
1289	Removes the given node at the given index in this element's list of child nodes (see the `children()` method). If the index is invalid, an Err result is returned, otherwise the removed node is return as an Ok result.
1290	 */
1291	pub fn remove(&mut self, index: usize) -> Result<Box<dyn Node>, IndexOutOfBounds> {
1292		if index >= self.child_nodes.len() {
1293			return Err(IndexOutOfBounds::new(index as isize, Some((0, self.child_nodes.len() as isize))));
1294		}
1295		Ok(self.child_nodes.remove(index))
1296	}
1297	/** Recursively removes all child nodes matching the given predicate function, returning the number of removed nodes.
1298
1299	This function is recursive, meaning that it will remove matching child nodes, child nodes of children, child nodes of children's children, etc. For non-recursive removal, use [remove_by(...)](remove_by()) instead.
1300
1301	# Example:
1302	```rust
1303	fn main() -> Result<(),kiss_xml::errors::KissXmlError> {
1304		use kiss_xml;
1305		let xml = r#"
1306		<list>
1307			<task>Go to work</task>
1308			<work>Web development</work>
1309			<task>Do homework</task>
1310			<task>Party!</task>
1311		</list>
1312		"#;
1313		let mut dom = kiss_xml::parse_str(xml)?;
1314		dom.root_element_mut().remove_all(
1315			&|n| n.text().contains("work")
1316		);
1317		println!("Fun list:\n{}", dom);
1318		// prints:
1319		// Fun list:
1320		// <list>
1321		//   <work>Web development</work>
1322		//   <task>Party!</task>
1323		// </list>
1324		Ok(())
1325	}
1326	```
1327	 */
1328	pub fn remove_all<P>(&mut self, predicate: &P) -> usize where P: Fn(&Box<dyn Node>) -> bool {
1329		let mut count =  self.remove_by(predicate);
1330		for e in self.child_elements_mut() {
1331			count += e.remove_all(predicate);
1332		}
1333		return count;
1334	}
1335
1336	/** Removes all child nodes matching the given predicate function, returning the number of removed nodes (non-recursive).
1337
1338	This function is not recursive. For recursive removal, use [remove_all(...)](remove_all()) instead.
1339	 */
1340	pub fn remove_by<P>(&mut self, predicate: &P) -> usize where P: Fn(&Box<dyn Node>) -> bool {
1341		let mut rm_indices: Vec<usize> = Vec::new();
1342		for i in (0..self.child_nodes.len()).rev() {
1343			if predicate(&self.child_nodes[i]) {
1344				rm_indices.push(i);
1345			}
1346		}
1347		let count =  rm_indices.len();
1348		for i in rm_indices {
1349			self.child_nodes.remove(i);
1350		}
1351		return count;
1352	}
1353	/** Removes the Nth child element from this element, returning it as a result (or an `IndexOutOfBounds` error result if the index is out of range) */
1354	pub fn remove_element(&mut self, index: usize) -> Result<Element, IndexOutOfBounds> {
1355		// first, index the child elements
1356		let mut elems: Vec<usize> = Vec::new();
1357		for i in 0..self.child_nodes.len() {
1358			if self.child_nodes[i].is_element(){ elems.push(i); }
1359		}
1360		// now remove the requested element
1361		if index >= elems.len() {
1362			return Err(IndexOutOfBounds::new(index as isize, Some((0, elems.len() as isize))));
1363		}
1364		let removed = self.child_nodes.remove(elems[index]);
1365		Ok(removed.as_element().expect("logic error").clone())
1366	}
1367	/** Removes all child elements matching the given predicate function, returning the number of removed elements.
1368
1369	This removal is non-recursive, meaning that it can only remove children of this element, not children-of-children. For a recursive removal, use [remove_all_elements(...)](remove_all_elements()) instead. */
1370	pub fn remove_elements<P>(&mut self, predicate: P) -> usize where P: Fn(&Element) -> bool {
1371		let mut rm_indices: Vec<usize> = Vec::new();
1372		for i in (0..self.child_nodes.len()).rev() {
1373			if self.child_nodes[i].is_element() {
1374				if predicate(
1375					self.child_nodes[i].as_element().expect("logic error")
1376				) {
1377					rm_indices.push(i);
1378				}
1379			}
1380		}
1381		let count =  rm_indices.len();
1382		for i in rm_indices {
1383			self.child_nodes.remove(i);
1384		}
1385		return count;
1386	}
1387
1388	/** Recursively removes all child nodes matching the given predicate function, returning the number of removed nodes.
1389
1390	This function is recursive, meaning that it will remove matching child nodes, child nodes of children, child nodes of children's children, etc. For non-recursive removal, use [remove_by(...)](remove_by()) instead.
1391	 */
1392	pub fn remove_all_elements<P>(&mut self, predicate: P) -> usize where P: Fn(&Element) -> bool {
1393		let new_pred = |n: &Box<dyn Node>| {
1394			match n.is_element(){
1395				true => predicate(n.as_element().unwrap()),
1396				false => false
1397			}
1398		};
1399		let mut count =  self.remove_by(&new_pred);
1400		for e in self.child_elements_mut() {
1401			count += e.remove_all(&new_pred);
1402		}
1403		return count;
1404	}
1405	/** Removes all child elements matching the given element name (regardless of namespace), returning the number of removed elements.
1406
1407	This removal is non-recursive, meaning that it can only remove children of this element, not children-of-children. For a recursive removal, use [remove_all_elements(...)](remove_all_elements()) instead. */
1408	pub fn remove_elements_by_name(&mut self, name: impl Into<String>) -> usize {
1409		let n: String = name.into();
1410		self.remove_elements(move |e| e.name == n)
1411	}
1412
1413	/// Implementation of writing DOM to XML string
1414	/// (inline = true to bypass pretty-printing
1415	fn to_string_with_prefix_and_indent(&self, prefix: &str, indent: &str, mut inline: bool) -> String {
1416		let mut out = String::new();
1417		if !inline {out.push_str(prefix)}
1418		// tag name
1419		let tag_name = self.tag_name();
1420		out.push_str("<");
1421		out.push_str(tag_name.as_str());
1422
1423		// attributes
1424		let mut attrs: Vec<(&String, &String)> = self.attributes().iter().map(|kv| (kv.0, kv.1)).collect();
1425		attrs.sort_by(crate::attribute_order);  // ensure consistent and predictable attribute ordering
1426		for (k, v) in attrs {
1427			out.push_str(" ");
1428			out.push_str(k.as_str());
1429			out.push_str("=\"");
1430			out.push_str(crate::attribute_escape(v).as_str());
1431			out.push_str("\"");
1432		}
1433		// children (or not)
1434		let child_count = self.child_nodes.len();
1435		if child_count == 0 {
1436			out.push_str("/>");
1437		} else if child_count == 1 && !self.child_nodes[0].is_element() {
1438			// single non-element child, display inline
1439			out.push_str(">");
1440			out.push_str(&self.child_nodes[0].to_string_with_indent(""));
1441			out.push_str("</");
1442			out.push_str(tag_name.as_str());
1443			out.push_str(">");
1444		} else {
1445			// multiple children, prettify
1446			out.push('>');
1447			/* here's where XML gets tricky and weird:
1448			We want to pretty-print with indentation, BUT ONLY if said indentation would be
1449			considered "insignificant" by a typical XML parser.
1450			Whitespace between elements is considered insignificant, UNLESS...
1451			" if the element is declared as having mixed content, both text and element child nodes,
1452			then the XML parser must pass on all the white space found within the element."
1453			-- http://usingxml.com/Basics/XmlSpace
1454			*/
1455			// check if this is a mixed element
1456			inline = inline || self.child_nodes.iter().any(|n| n.is_text());
1457			if !inline{out.push('\n');}
1458			// prettify variables
1459			let mut next_prefix = String::from(prefix);
1460			next_prefix.push_str(indent);
1461			for c in &self.child_nodes {
1462				if c.is_text() {
1463					// text is always inline
1464					let text = crate::text_escape(c.text());
1465					out.push_str(text.as_str());
1466				} else if c.is_element() {
1467					// child element, recurse
1468					out.push_str(
1469						c.as_element().expect("logic error")
1470							.to_string_with_prefix_and_indent(next_prefix.as_str(), indent, inline).as_str()
1471					);
1472				} else {
1473					// other
1474					if !(inline) {out.push_str(next_prefix.as_str());}
1475					out.push_str(c.to_string_with_indent(indent).as_str());
1476				}
1477				if !inline {out.push('\n');}
1478			}
1479			// closing tag
1480			if !inline {out.push_str(prefix);}
1481			out.push_str("</");
1482			out.push_str(tag_name.as_str());
1483			out.push_str(">");
1484		}
1485		return out;
1486	}
1487
1488}
1489
1490impl Node for Element {
1491
1492	fn text(&self) -> String {
1493		// Note: this is recursive, but only elements and text nodes
1494		let mut builder = String::new();
1495		for c in &self.child_nodes {
1496			if c.is_text() || c.is_element() {
1497				builder.push_str(c.text().as_str())
1498			}
1499		}
1500		builder
1501	}
1502
1503	fn is_element(&self) -> bool {
1504		true
1505	}
1506
1507	fn is_text(&self) -> bool {
1508		false
1509	}
1510
1511	fn is_comment(&self) -> bool {
1512		false
1513	}
1514
1515	fn is_cdata(&self) -> bool {
1516		false
1517	}
1518
1519	fn as_element(&self) -> Result<&Element, TypeCastError> {Ok(&self)}
1520
1521	fn as_comment(&self) -> Result<&Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as Comment"))}
1522
1523	fn as_text(&self) -> Result<&Text, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as Text"))}
1524
1525	fn as_cdata(&self) -> Result<&CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as CData"))}
1526
1527	fn as_element_mut(&mut self) -> Result<&mut Element, TypeCastError> {Ok(self)}
1528
1529	fn as_comment_mut(&mut self) -> Result<&mut Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as Comment"))}
1530
1531	fn as_text_mut(&mut self) -> Result<&mut Text, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as Text"))}
1532
1533	fn as_cdata_mut(&mut self) -> Result<&mut CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Element as CData"))}
1534
1535	fn as_node(&self) -> &dyn Node {self}
1536
1537	fn as_node_mut(&mut self) -> &mut dyn Node {self}
1538
1539	fn as_any(&self) -> &dyn Any {self}
1540
1541	fn as_any_mut(&mut self) -> &mut dyn Any{self}
1542
1543	fn to_string_with_indent(&self, indent: &str) -> String {
1544		match crate::validate_indent(indent){
1545			Ok(_) => self.to_string_with_prefix_and_indent("", indent, false),
1546			Err(_) => {
1547				eprintln!("WARNING: {:?} is not a valid indentation. Must be either 1 tab or any number of spaces. The default of 2 spaces will be used instead", indent);
1548				self.to_string_with_prefix_and_indent("", "  ", false)
1549			}
1550		}
1551	}
1552
1553	fn boxed(self) -> Box<dyn Node> {
1554		Box::new(self)
1555	}
1556}
1557
1558impl Clone for Element {
1559	fn clone(&self) -> Self {
1560		let mut new_children: Vec<Box<dyn Node>> = Vec::with_capacity(self.child_nodes.len());
1561		for c in &self.child_nodes {
1562			new_children.push(clone_node(c))
1563		}
1564		Self {
1565			name: self.name.clone(),
1566			child_nodes: new_children,
1567			attributes: self.attributes.clone(),
1568			xmlns: self.xmlns.clone(),
1569			xmlns_prefix: self.xmlns_prefix.clone(),
1570			xmlns_context: self.xmlns_context.clone(),
1571		}
1572	}
1573}
1574
1575impl Default for Element {
1576	fn default() -> Self {
1577		Self {
1578			name: "x".to_string(),
1579			child_nodes: Vec::new(),
1580			attributes: Default::default(),
1581			xmlns: None,
1582			xmlns_prefix: None,
1583			xmlns_context: HashMap::new(),
1584		}
1585	}
1586}
1587
1588impl PartialOrd for Element {
1589	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1590		self.name.partial_cmp(&other.name)
1591	}
1592}
1593
1594impl PartialEq<Self> for Element {
1595	fn eq(&self, other: &Self) -> bool {
1596		if self.name == other.name && self.xmlns == other.xmlns
1597			&& self.xmlns_prefix == other.xmlns_prefix
1598			&& self.attributes == other.attributes
1599			&& self.child_nodes.len() == other.child_nodes.len() {
1600			for i in 0..self.child_nodes.len() {
1601				if !node_eq(&self.child_nodes[i], &other.child_nodes[i]) {
1602					return false;
1603				}
1604			}
1605			return true;
1606		}
1607		return false;
1608	}
1609}
1610
1611impl Hash for Element {
1612	fn hash<H: Hasher>(&self, state: &mut H) {
1613		self.name.hash(state);
1614		self.xmlns.hash(state);
1615	}
1616}
1617
1618
1619impl std::fmt::Display for Element {
1620	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1621		write!(f, "{}", self.to_string_with_indent("  "))
1622	}
1623}
1624
1625impl std::fmt::Debug for Element {
1626	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1627		write!(f, "{}", self.to_string_with_indent("  "))
1628	}
1629}
1630
1631/// Represents a string of text in the XML DOM
1632#[derive(Clone)]
1633pub struct Text {
1634	/// The content of this Text node
1635	pub content: String
1636}
1637
1638/// singleton regex matcher
1639const WSP_MATCHER_SINGLETON: OnceCell<Regex> = OnceCell::new();
1640
1641impl Text {
1642	/** Construct a new Text node from the provided string-like object */
1643	pub fn new(text: impl Into<String>) -> Self {
1644		let content: String = text.into();
1645		Self{content}
1646	}
1647
1648	/** Returns a new Text node that is equivalent to this one plus the given Text node */
1649	pub fn concat(&self, other: &Text) -> Text {
1650		let mut content = String::new();
1651		content.push_str(self.content.as_str());
1652		content.push_str(other.content.as_str());
1653		Text{content}
1654	}
1655
1656	/// checks if this Text node contains only whitespace
1657	fn is_whitespace(&self) -> bool {
1658		let singleton = WSP_MATCHER_SINGLETON;
1659		let wsp_matcher = singleton.get_or_init(|| Regex::new(r#"^\s+$"#).unwrap());
1660		wsp_matcher.is_match(self.content.as_str())
1661	}
1662}
1663
1664impl From<&str> for Text {
1665	fn from(value: &str) -> Self {
1666		Text::new(value)
1667	}
1668}
1669
1670impl From<String> for Text {
1671	fn from(value: String) -> Self {
1672		Text::new(value)
1673	}
1674}
1675
1676impl Node for Text {
1677
1678	fn text(&self) -> String {
1679		self.content.clone()
1680	}
1681
1682	fn is_element(&self) -> bool {
1683		false
1684	}
1685
1686	fn is_text(&self) -> bool {
1687		true
1688	}
1689
1690	fn is_comment(&self) -> bool {
1691		false
1692	}
1693
1694	fn is_cdata(&self) -> bool {
1695		false
1696	}
1697
1698	fn as_element(&self) -> Result<&Element, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as Element"))}
1699
1700	fn as_comment(&self) -> Result<&Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as Comment"))}
1701
1702	fn as_text(&self) -> Result<&Text, TypeCastError> {Ok(&self)}
1703
1704	fn as_cdata(&self) -> Result<&CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as CData"))}
1705
1706	fn as_element_mut(&mut self) -> Result<&mut Element, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as Element"))}
1707
1708	fn as_comment_mut(&mut self) -> Result<&mut Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as Comment"))}
1709
1710	fn as_text_mut(&mut self) -> Result<&mut Text, TypeCastError> {Ok(self)}
1711
1712	fn as_cdata_mut(&mut self) -> Result<&mut CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Text as CData"))}
1713
1714	fn as_node(&self) -> &dyn Node {self}
1715
1716	fn as_node_mut(&mut self) -> &mut dyn Node {self}
1717
1718	fn as_any(&self) -> &dyn Any {self}
1719
1720	fn as_any_mut(&mut self) -> &mut dyn Any{self}
1721
1722	fn to_string_with_indent(&self, _indent: &str) -> String {
1723		crate::text_escape(self.content.clone())
1724	}
1725
1726	fn boxed(self) -> Box<dyn Node> {
1727		Box::new(self)
1728	}
1729}
1730
1731impl PartialOrd for Text {
1732	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1733		self.content.partial_cmp(&other.content)
1734	}
1735}
1736
1737impl PartialEq<Self> for Text {
1738	fn eq(&self, other: &Self) -> bool {
1739		self.content.eq(&other.content)
1740	}
1741}
1742
1743impl Hash for Text {
1744	fn hash<H: Hasher>(&self, state: &mut H) {
1745		self.content.hash(state)
1746	}
1747}
1748
1749
1750impl std::fmt::Display for Text {
1751	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1752		write!(f, "{}", self.to_string_with_indent("  "))
1753	}
1754}
1755
1756impl std::fmt::Debug for Text {
1757	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1758		write!(f, "{}", self.to_string_with_indent("  "))
1759	}
1760}
1761
1762/// Represents an XML comment
1763#[derive(Clone)]
1764pub struct Comment{
1765	/// The text of the comment
1766	comment: String
1767}
1768
1769impl Comment {
1770	/// Constructs a new Comment node from the given string-like object
1771	pub fn new(comment: impl Into<String>) -> Result<Self, InvalidContent> {
1772		let content: String = comment.into();
1773		if content.contains("-->") {
1774			Err(InvalidContent::new("Comments cannot contain '-->'"))
1775		} else {
1776			Ok(Self { comment: content })
1777		}
1778	}
1779
1780	/// Gets the content of this comment
1781	pub fn get_content(&self) -> &str {
1782		self.comment.as_str()
1783	}
1784	/// Sets the content of this comment
1785	pub fn set_content(&mut self, content: impl Into<String>) -> Result<(), InvalidContent> {
1786		let content = content.into();
1787		if content.contains("-->") {
1788			Err(InvalidContent::new("Comments cannot contain '-->'"))
1789		} else {
1790			self.comment = content.into();
1791			Ok(())
1792		}
1793	}
1794}
1795
1796impl Node for Comment {
1797
1798	fn text(&self) -> String {
1799		self.comment.clone()
1800	}
1801
1802	fn is_element(&self) -> bool {
1803		false
1804	}
1805
1806	fn is_text(&self) -> bool {
1807		false
1808	}
1809
1810	fn is_comment(&self) -> bool {
1811		true
1812	}
1813
1814	fn is_cdata(&self) -> bool {
1815		false
1816	}
1817
1818	fn as_element(&self) -> Result<&Element, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as Element"))}
1819
1820	fn as_comment(&self) -> Result<&Comment, TypeCastError> {Ok(&self)}
1821
1822	fn as_text(&self) -> Result<&Text, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as Text"))}
1823
1824	fn as_cdata(&self) -> Result<&CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as CData"))}
1825
1826	fn as_element_mut(&mut self) -> Result<&mut Element, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as Element"))}
1827
1828	fn as_comment_mut(&mut self) -> Result<&mut Comment, TypeCastError> {Ok(self)}
1829
1830	fn as_text_mut(&mut self) -> Result<&mut Text, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as Text"))}
1831
1832	fn as_cdata_mut(&mut self) -> Result<&mut CData, TypeCastError> {Err(TypeCastError::new("Cannot cast Comment as CData"))}
1833
1834	fn as_node(&self) -> &dyn Node {self}
1835
1836	fn as_node_mut(&mut self) -> &mut dyn Node {self}
1837
1838	fn as_any(&self) -> &dyn Any {self}
1839
1840	fn as_any_mut(&mut self) -> &mut dyn Any{self}
1841
1842	fn to_string_with_indent(&self, _indent: &str) -> String {
1843		format!("<!--{}-->", self.comment)
1844	}
1845
1846	fn boxed(self) -> Box<dyn Node> {
1847		Box::new(self)
1848	}
1849}
1850
1851impl From<&str> for Comment {
1852	fn from(value: &str) -> Self {
1853		Comment::new(value).unwrap()
1854	}
1855}
1856
1857impl From<String> for Comment {
1858	fn from(value: String) -> Self {
1859		Comment::new(value).unwrap()
1860	}
1861}
1862
1863impl PartialOrd for Comment {
1864	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1865		self.comment.partial_cmp(&other.comment)
1866	}
1867}
1868
1869impl PartialEq<Self> for Comment {
1870	fn eq(&self, other: &Self) -> bool {
1871		self.comment.eq(&other.comment)
1872	}
1873}
1874
1875impl Hash for Comment {
1876	fn hash<H: Hasher>(&self, state: &mut H) {
1877		self.comment.hash(state)
1878	}
1879}
1880
1881impl std::fmt::Display for Comment {
1882	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1883		write!(f, "{}", self.to_string_with_indent("  "))
1884	}
1885}
1886
1887impl std::fmt::Debug for Comment {
1888	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1889		write!(f, "{}", self.to_string_with_indent("  "))
1890	}
1891}
1892
1893/** This struct represents a CData element. CData is text data that should be preserved as-is without escaping or whitespace modification. CData is *not* binary data (though some non-standard uses of XML may store binary data in a CData tag) */
1894#[derive(Clone)]
1895pub struct CData{
1896	/// The content of the cdata
1897	cdata: String
1898}
1899
1900impl CData {
1901	/// Constructs a new CData node from the given string-like object
1902	pub fn new(cdata: impl Into<String>) -> Result<Self, InvalidContent> {
1903		let content: String = cdata.into();
1904		if content.contains("]]>") {
1905			Err(InvalidContent::new("CDATA cannot contain ']]>' as content"))
1906		} else {
1907			Ok(Self { cdata: content })
1908		}
1909	}
1910
1911	/// Sets the content of this CDATA
1912	pub fn set_text(&mut self, content: impl Into<String>) -> Result<(), InvalidContent> {
1913		let content = content.into();
1914		if content.contains("]]>") {
1915			Err(InvalidContent::new("CDATA cannot contain ']]>'"))
1916		} else {
1917			self.cdata = content.into();
1918			Ok(())
1919		}
1920	}
1921
1922	/// Gets the content of this CDATA
1923	pub fn get_content(&self) -> &str {
1924		self.cdata.as_str()
1925	}
1926}
1927
1928impl Node for CData {
1929
1930	fn text(&self) -> String {
1931		self.cdata.clone()
1932	}
1933
1934	fn is_element(&self) -> bool {
1935		false
1936	}
1937
1938	fn is_text(&self) -> bool {
1939		false
1940	}
1941
1942	fn is_comment(&self) -> bool {
1943		false
1944	}
1945
1946	fn is_cdata(&self) -> bool {
1947		true
1948	}
1949
1950	fn as_element(&self) -> Result<&Element, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Element"))}
1951
1952	fn as_comment(&self) -> Result<&Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Comment"))}
1953
1954	fn as_text(&self) -> Result<&Text, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Text"))}
1955
1956	fn as_cdata(&self) -> Result<&CData, TypeCastError> {Ok(&self)}
1957
1958	fn as_element_mut(&mut self) -> Result<&mut Element, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Element"))}
1959
1960	fn as_comment_mut(&mut self) -> Result<&mut Comment, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Comment"))}
1961
1962	fn as_text_mut(&mut self) -> Result<&mut Text, TypeCastError> {Err(TypeCastError::new("Cannot cast CData as Text"))}
1963
1964	fn as_cdata_mut(&mut self) -> Result<&mut CData, TypeCastError> {Ok(self)}
1965
1966	fn as_node(&self) -> &dyn Node {self}
1967
1968	fn as_node_mut(&mut self) -> &mut dyn Node {self}
1969
1970	fn as_any(&self) -> &dyn Any {self}
1971
1972	fn as_any_mut(&mut self) -> &mut dyn Any{self}
1973
1974	fn to_string_with_indent(&self, _indent: &str) -> String {
1975		format!("<![CDATA[{}]]>", self.cdata)
1976	}
1977
1978	fn boxed(self) -> Box<dyn Node> {
1979		Box::new(self)
1980	}
1981}
1982
1983impl From<&str> for CData {
1984	fn from(value: &str) -> Self {
1985		CData::new(value).unwrap()
1986	}
1987}
1988
1989impl From<String> for CData {
1990	fn from(value: String) -> Self {
1991		CData::new(value).unwrap()
1992	}
1993}
1994
1995impl PartialOrd for CData {
1996	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1997		self.cdata.partial_cmp(&other.cdata)
1998	}
1999}
2000
2001impl PartialEq<Self> for CData {
2002	fn eq(&self, other: &Self) -> bool {
2003		self.cdata.eq(&other.cdata)
2004	}
2005}
2006
2007impl Hash for CData {
2008	fn hash<H: Hasher>(&self, state: &mut H) {
2009		self.cdata.hash(state)
2010	}
2011}
2012
2013impl std::fmt::Display for CData {
2014	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2015		write!(f, "{}", self.to_string_with_indent("  "))
2016	}
2017}
2018
2019impl std::fmt::Debug for CData {
2020	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2021		write!(f, "{}", self.to_string_with_indent("  "))
2022	}
2023}
2024
2025
2026/** An XML document declaration, ie `<?xml version="1.0" encoding="UTF-8"?>`
2027
2028`kiss_xml` does not interpret XML document declarations and does not require XML documents to have one. The declaration will simply be copied verbatum. */
2029#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2030pub struct Declaration {
2031	decl_str: String
2032}
2033
2034impl Declaration {
2035	/// Creates a new Declaration from the given string (eg `<?xml version="1.0" encoding="UTF-8"?>`)
2036	pub fn from_str(decl: &str) -> Result<Self, KissXmlError> {
2037		// parsing XML declarations is beyond the scope of the kiss_xml crate
2038		let buffer: String = decl.trim().to_string();
2039		if buffer.starts_with("<?") && buffer.ends_with("?>"){
2040			Ok(Self{decl_str: buffer.strip_prefix("<?").unwrap().strip_suffix("?>").unwrap().to_string()})
2041		} else {
2042			Err(ParsingError::new("Invalid XML declaration syntax").into())
2043		}
2044	}
2045	/// Creates a new standard Declaration (UTF-8 encoded XML version 1)
2046	pub fn new() -> Self {
2047		Self::default()
2048	}
2049}
2050
2051impl Default for Declaration {
2052	fn default() -> Self {
2053		Declaration::from_str(r#"<?xml version="1.0" encoding="UTF-8"?>"#).unwrap()
2054	}
2055}
2056
2057impl std::fmt::Display for Declaration {
2058	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2059		write!(f, "<?{}?>", self.decl_str)
2060	}
2061}
2062
2063impl std::fmt::Debug for Declaration {
2064	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2065		write!(f, "<?{}?>", self.decl_str)
2066	}
2067}
2068
2069/**
2070An XML document type declaration (DTD) defines custom behavior for XML documents, but `kiss_xml` does not support DTDs beyond copying them verbatum.
2071*/
2072#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2073pub struct DTD {
2074	dtd_str: String
2075}
2076
2077impl DTD {
2078	/// Creates a new DTD from the given string (eg `<!DOCTYPE note []>)
2079	pub fn from_string(text: impl Into<String>) -> Result<DTD, KissXmlError> {
2080		// parsing DTDs is beyond the scope of the kiss_xml crate
2081		let buffer: String = text.into().trim().to_string();
2082		if buffer.starts_with("<!DOCTYPE") && buffer.ends_with(">"){
2083			Ok(Self{dtd_str: buffer.strip_prefix("<!DOCTYPE").unwrap().strip_suffix(">").unwrap().to_string()})
2084		} else {
2085			Err(ParsingError::new("Invalid DTD syntax").into())
2086		}
2087	}
2088}
2089
2090impl std::fmt::Display for DTD {
2091	fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2092		write!(f, "{}", self.dtd_str)
2093	}
2094}