1// Copyright (c) 2020 lumi <lumi@pew.im>
2// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
3// Copyright (c) 2020 Bastien Orivel <eijebong+minidom@bananium.fr>
4// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
5// Copyright (c) 2020 Yue Liu <amznyue@amazon.com>
6// Copyright (c) 2020 Matt Bilker <me@mbilker.us>
7// Copyright (c) 2020 Xidorn Quan <me@upsuper.org>
8//
9// This Source Code Form is subject to the terms of the Mozilla Public
10// License, v. 2.0. If a copy of the MPL was not distributed with this
11// file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
13//! Provides an `Element` type, which represents DOM nodes, and a builder to create them with.
14
15use crate::convert::IntoAttributeValue;
16use crate::error::{Error, Result};
17use crate::namespaces::NSChoice;
18use crate::node::Node;
19use crate::prefixes::{Namespace, Prefix, Prefixes};
20use crate::tree_builder::TreeBuilder;
21
22use alloc::borrow::Cow;
23use alloc::collections::btree_map::{self, BTreeMap};
24use alloc::string::String;
25use alloc::vec::Vec;
26
27use core::slice;
28use core::str::FromStr;
29
30use std::io;
31
32use rxml::writer::{Encoder, Item, TrackNamespace};
33use rxml::{Namespace as RxmlNamespace, RawReader, XmlVersion};
34
35fn encode_and_write<W: io::Write, T: rxml::writer::TrackNamespace>(
36 item: Item<'_>,
37 enc: &mut Encoder<T>,
38 mut w: W,
39) -> io::Result<()> {
40 let mut buf = rxml::bytes::BytesMut::new();
41 enc.encode_into_bytes(item, &mut buf)
42 .expect("encoder driven incorrectly");
43 w.write_all(&buf[..])?;
44 Ok(())
45}
46
47/// Wrapper around a [`io::Write`] and an [`rxml::writer::Encoder`], to
48/// provide a simple function to write an rxml Item to a writer.
49pub struct CustomItemWriter<W, T> {
50 writer: W,
51 encoder: Encoder<T>,
52}
53
54impl<W: io::Write> CustomItemWriter<W, rxml::writer::SimpleNamespaces> {
55 pub(crate) fn new(writer: W) -> Self {
56 Self {
57 writer,
58 encoder: Encoder::new(),
59 }
60 }
61}
62
63impl<W: io::Write, T: rxml::writer::TrackNamespace> CustomItemWriter<W, T> {
64 pub(crate) fn write(&mut self, item: Item<'_>) -> io::Result<()> {
65 encode_and_write(item, &mut self.encoder, &mut self.writer)
66 }
67}
68
69/// Type alias to simplify the use for the default namespace tracking
70/// implementation.
71pub type ItemWriter<W> = CustomItemWriter<W, rxml::writer::SimpleNamespaces>;
72
73/// helper function to escape a `&[u8]` and replace all
74/// xml special characters (<, >, &, ', ") with their corresponding
75/// xml escaped value.
76#[must_use]
77pub fn escape(raw: &[u8]) -> Cow<'_, [u8]> {
78 fn to_escape(b: u8) -> bool {
79 matches!(b, b'<' | b'>' | b'\'' | b'&' | b'"')
80 }
81
82 let mut escapes: Vec<(usize, &'static [u8])> = Vec::new();
83 let mut bytes = raw.iter();
84 let mut loc = 0;
85 while let Some(i) = bytes.position(|&b| to_escape(b)) {
86 loc += i;
87 match raw[loc] {
88 b'<' => escapes.push((loc, b"<")),
89 b'>' => escapes.push((loc, b">")),
90 b'\'' => escapes.push((loc, b"'")),
91 b'&' => escapes.push((loc, b"&")),
92 b'"' => escapes.push((loc, b""")),
93 _ => unreachable!("Only '<', '>', '\'', '&' and '\"' are escaped"),
94 }
95 loc += 1;
96 }
97
98 if escapes.is_empty() {
99 Cow::Borrowed(raw)
100 } else {
101 let len = raw.len();
102 let mut v = Vec::with_capacity(len);
103 let mut start = 0;
104 for (i, r) in escapes {
105 v.extend_from_slice(&raw[start..i]);
106 v.extend_from_slice(r);
107 start = i + 1;
108 }
109
110 if start < len {
111 v.extend_from_slice(&raw[start..]);
112 }
113 Cow::Owned(v)
114 }
115}
116
117#[derive(Clone, Eq, Debug)]
118/// A struct representing a DOM Element.
119pub struct Element {
120 name: String,
121 namespace: String,
122 /// Namespace declarations
123 pub prefixes: Prefixes,
124 attributes: BTreeMap<String, String>,
125 children: Vec<Node>,
126}
127
128impl<'a> From<&'a Element> for String {
129 fn from(elem: &'a Element) -> String {
130 let mut writer = Vec::new();
131 elem.write_to(&mut writer).unwrap();
132 String::from_utf8(writer).unwrap()
133 }
134}
135
136impl FromStr for Element {
137 type Err = Error;
138
139 fn from_str(s: &str) -> Result<Element> {
140 Element::from_reader(s.as_bytes())
141 }
142}
143
144impl PartialEq for Element {
145 fn eq(&self, other: &Self) -> bool {
146 if self.name() == other.name() && self.ns() == other.ns() && self.attrs().eq(other.attrs())
147 {
148 if self.nodes().count() != other.nodes().count() {
149 return false;
150 }
151 self.nodes()
152 .zip(other.nodes())
153 .all(|(node1, node2)| node1 == node2)
154 } else {
155 false
156 }
157 }
158}
159
160impl Element {
161 pub(crate) fn new<P: Into<Prefixes>>(
162 name: String,
163 namespace: String,
164 prefixes: P,
165 attributes: BTreeMap<String, String>,
166 children: Vec<Node>,
167 ) -> Element {
168 Element {
169 name,
170 namespace,
171 prefixes: prefixes.into(),
172 attributes,
173 children,
174 }
175 }
176
177 /// Return a builder for an `Element` with the given `name`.
178 ///
179 /// # Examples
180 ///
181 /// ```rust
182 /// use minidom::Element;
183 ///
184 /// let elem = Element::builder("name", "namespace")
185 /// .attr("name", "value")
186 /// .append("inner")
187 /// .build();
188 ///
189 /// assert_eq!(elem.name(), "name");
190 /// assert_eq!(elem.ns(), "namespace".to_owned());
191 /// assert_eq!(elem.attr("name"), Some("value"));
192 /// assert_eq!(elem.attr("inexistent"), None);
193 /// assert_eq!(elem.text(), "inner");
194 /// ```
195 pub fn builder<S: AsRef<str>, NS: Into<String>>(name: S, namespace: NS) -> ElementBuilder {
196 ElementBuilder {
197 root: Element::new(
198 name.as_ref().to_string(),
199 namespace.into(),
200 None,
201 BTreeMap::new(),
202 Vec::new(),
203 ),
204 }
205 }
206
207 /// Returns a bare minimum `Element` with this name.
208 ///
209 /// # Examples
210 ///
211 /// ```rust
212 /// use minidom::Element;
213 ///
214 /// let bare = Element::bare("name", "namespace");
215 ///
216 /// assert_eq!(bare.name(), "name");
217 /// assert_eq!(bare.ns(), "namespace");
218 /// assert_eq!(bare.attr("name"), None);
219 /// assert_eq!(bare.text(), "");
220 /// ```
221 pub fn bare<S: Into<String>, NS: Into<String>>(name: S, namespace: NS) -> Element {
222 Element::new(
223 name.into(),
224 namespace.into(),
225 None,
226 BTreeMap::new(),
227 Vec::new(),
228 )
229 }
230
231 /// Returns a reference to the local name of this element (that is, without a possible prefix).
232 #[must_use]
233 pub fn name(&self) -> &str {
234 &self.name
235 }
236
237 /// Returns a reference to the namespace of this element.
238 #[must_use]
239 pub fn ns(&self) -> String {
240 self.namespace.clone()
241 }
242
243 /// Returns a reference to the value of the given attribute, if it exists, else `None`.
244 #[must_use]
245 pub fn attr(&self, name: &str) -> Option<&str> {
246 if let Some(value) = self.attributes.get(name) {
247 return Some(value);
248 }
249 None
250 }
251
252 /// Returns an iterator over the attributes of this element.
253 ///
254 /// # Example
255 ///
256 /// ```rust
257 /// use minidom::Element;
258 ///
259 /// let elm: Element = "<elem xmlns=\"ns1\" a=\"b\" />".parse().unwrap();
260 ///
261 /// let mut iter = elm.attrs();
262 ///
263 /// assert_eq!(iter.next().unwrap(), ("a", "b"));
264 /// assert_eq!(iter.next(), None);
265 /// ```
266 #[must_use]
267 pub fn attrs(&self) -> Attrs<'_> {
268 Attrs {
269 iter: self.attributes.iter(),
270 }
271 }
272
273 /// Returns an iterator over the attributes of this element, with the value being a mutable
274 /// reference.
275 #[must_use]
276 pub fn attrs_mut(&mut self) -> AttrsMut<'_> {
277 AttrsMut {
278 iter: self.attributes.iter_mut(),
279 }
280 }
281
282 /// Modifies the value of an attribute.
283 pub fn set_attr<S: Into<String>, V: IntoAttributeValue>(&mut self, name: S, val: V) {
284 let name = name.into();
285 let val = val.into_attribute_value();
286
287 if let Some(value) = self.attributes.get_mut(&name) {
288 *value = val
289 .expect("removing existing value via set_attr, this is not yet supported (TODO)"); // TODO
290 return;
291 }
292
293 if let Some(val) = val {
294 self.attributes.insert(name, val);
295 }
296 }
297
298 /// Returns whether the element has the given name and namespace.
299 ///
300 /// # Examples
301 ///
302 /// ```rust
303 /// use minidom::{Element, NSChoice};
304 ///
305 /// let elem = Element::builder("name", "namespace").build();
306 ///
307 /// assert_eq!(elem.is("name", "namespace"), true);
308 /// assert_eq!(elem.is("name", "wrong"), false);
309 /// assert_eq!(elem.is("wrong", "namespace"), false);
310 /// assert_eq!(elem.is("wrong", "wrong"), false);
311 ///
312 /// assert_eq!(elem.is("name", NSChoice::OneOf("namespace")), true);
313 /// assert_eq!(elem.is("name", NSChoice::OneOf("foo")), false);
314 /// assert_eq!(elem.is("name", NSChoice::AnyOf(&["foo", "namespace"])), true);
315 /// assert_eq!(elem.is("name", NSChoice::Any), true);
316 /// ```
317 pub fn is<'a, N: AsRef<str>, NS: Into<NSChoice<'a>>>(&self, name: N, namespace: NS) -> bool {
318 self.name == name.as_ref() && namespace.into().compare(self.namespace.as_ref())
319 }
320
321 /// Returns whether the element has the given namespace.
322 ///
323 /// # Examples
324 ///
325 /// ```rust
326 /// use minidom::{Element, NSChoice};
327 ///
328 /// let elem = Element::builder("name", "namespace").build();
329 ///
330 /// assert_eq!(elem.has_ns("namespace"), true);
331 /// assert_eq!(elem.has_ns("wrong"), false);
332 ///
333 /// assert_eq!(elem.has_ns(NSChoice::OneOf("namespace")), true);
334 /// assert_eq!(elem.has_ns(NSChoice::OneOf("foo")), false);
335 /// assert_eq!(elem.has_ns(NSChoice::AnyOf(&["foo", "namespace"])), true);
336 /// assert_eq!(elem.has_ns(NSChoice::Any), true);
337 /// ```
338 pub fn has_ns<'a, NS: Into<NSChoice<'a>>>(&self, namespace: NS) -> bool {
339 namespace.into().compare(self.namespace.as_ref())
340 }
341
342 /// Parse a document from a `io::BufRead`.
343 pub fn from_reader<R: io::BufRead>(reader: R) -> Result<Element> {
344 let mut tree_builder = TreeBuilder::new();
345 let mut driver = RawReader::new(reader);
346 while let Some(event) = driver.read()? {
347 tree_builder.process_event(event)?;
348
349 if let Some(root) = tree_builder.root.take() {
350 return Ok(root);
351 }
352 }
353 Err(Error::EndOfDocument)
354 }
355
356 /// Parse a document from a `io::BufRead`, allowing Prefixes to be specified. Useful to provide
357 /// knowledge of namespaces that would have been declared on parent elements not present in the
358 /// reader.
359 pub fn from_reader_with_prefixes<R: io::BufRead, P: Into<Prefixes>>(
360 reader: R,
361 prefixes: P,
362 ) -> Result<Element> {
363 let mut tree_builder = TreeBuilder::new().with_prefixes_stack([prefixes.into()].into());
364 let mut driver = RawReader::new(reader);
365 while let Some(event) = driver.read()? {
366 tree_builder.process_event(event)?;
367
368 if let Some(root) = tree_builder.root.take() {
369 return Ok(root);
370 }
371 }
372 Err(Error::EndOfDocument)
373 }
374
375 /// Output a document to a `io::Writer`.
376 pub fn write_to<W: io::Write>(&self, writer: &mut W) -> Result<()> {
377 self.to_writer(&mut ItemWriter::new(writer))
378 }
379
380 /// Output a document to a `io::Writer`.
381 pub fn write_to_decl<W: io::Write>(&self, writer: &mut W) -> Result<()> {
382 self.to_writer_decl(&mut ItemWriter::new(writer))
383 }
384
385 /// Output the document to an `ItemWriter`
386 pub fn to_writer<W: io::Write>(&self, writer: &mut ItemWriter<W>) -> Result<()> {
387 self.write_to_inner(writer)
388 }
389
390 /// Output the document to an `ItemWriter`
391 pub fn to_writer_decl<W: io::Write>(&self, writer: &mut ItemWriter<W>) -> Result<()> {
392 writer
393 .write(Item::XmlDeclaration(XmlVersion::V1_0))
394 .unwrap(); // TODO: error return
395 self.write_to_inner(writer)
396 }
397
398 /// Like `write_to()` but without the `<?xml?>` prelude
399 pub fn write_to_inner<W: io::Write>(&self, writer: &mut ItemWriter<W>) -> Result<()> {
400 for (prefix, namespace) in self.prefixes.declared_prefixes() {
401 assert!(writer.encoder.ns_tracker_mut().declare_fixed(
402 prefix.as_deref().map(TryInto::try_into).transpose()?,
403 namespace.clone().into(),
404 ));
405 }
406
407 let namespace: RxmlNamespace = self.namespace.clone().into();
408 writer.write(Item::ElementHeadStart(&namespace, (*self.name).try_into()?))?;
409
410 for (key, value) in &self.attributes {
411 let (prefix, name) = <&rxml::NameStr>::try_from(&**key)
412 .unwrap()
413 .split_name()
414 .unwrap();
415 let namespace = match prefix {
416 Some(prefix) => match writer.encoder.ns_tracker().lookup_prefix(Some(prefix)) {
417 Ok(v) => v,
418 Err(rxml::writer::PrefixError::Undeclared) => return Err(Error::InvalidPrefix),
419 },
420 None => RxmlNamespace::NONE,
421 };
422 writer.write(Item::Attribute(&namespace, name, value))?;
423 }
424
425 if !self.children.is_empty() {
426 writer.write(Item::ElementHeadEnd)?;
427 for child in &self.children {
428 child.write_to_inner(writer)?;
429 }
430 }
431 writer.write(Item::ElementFoot)?;
432
433 Ok(())
434 }
435
436 /// Extracts all children into a collection.
437 pub fn take_nodes(&mut self) -> Vec<Node> {
438 self.children.drain(..).collect()
439 }
440
441 /// Returns an iterator over references to every child node of this element.
442 ///
443 /// # Examples
444 ///
445 /// ```rust
446 /// use minidom::Element;
447 ///
448 /// let elem: Element = "<root xmlns=\"ns1\">a<c1 />b<c2 />c</root>".parse().unwrap();
449 ///
450 /// let mut iter = elem.nodes();
451 ///
452 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "a");
453 /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c1");
454 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "b");
455 /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c2");
456 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "c");
457 /// assert_eq!(iter.next(), None);
458 /// ```
459 #[inline]
460 pub fn nodes(&self) -> Nodes<'_> {
461 self.children.iter()
462 }
463
464 /// Returns an iterator over mutable references to every child node of this element.
465 #[inline]
466 pub fn nodes_mut(&mut self) -> NodesMut<'_> {
467 self.children.iter_mut()
468 }
469
470 /// Returns an iterator over references to every child element of this element.
471 ///
472 /// # Examples
473 ///
474 /// ```rust
475 /// use minidom::Element;
476 ///
477 /// let elem: Element = "<root xmlns=\"ns1\">hello<child1 xmlns=\"ns1\"/>this<child2 xmlns=\"ns1\"/>is<child3 xmlns=\"ns1\"/>ignored</root>".parse().unwrap();
478 ///
479 /// let mut iter = elem.children();
480 /// assert_eq!(iter.next().unwrap().name(), "child1");
481 /// assert_eq!(iter.next().unwrap().name(), "child2");
482 /// assert_eq!(iter.next().unwrap().name(), "child3");
483 /// assert_eq!(iter.next(), None);
484 /// ```
485 #[inline]
486 #[must_use]
487 pub fn children(&self) -> Children<'_> {
488 Children {
489 iter: self.children.iter(),
490 }
491 }
492
493 /// Returns an iterator over mutable references to every child element of this element.
494 #[inline]
495 #[must_use]
496 pub fn children_mut(&mut self) -> ChildrenMut<'_> {
497 ChildrenMut {
498 iter: self.children.iter_mut(),
499 }
500 }
501
502 /// Returns an iterator over the child Elements, draining the element of
503 /// all its child nodes **including text!**
504 ///
505 /// This is a bit of a footgun, so we make this hidden in the docs (it
506 /// needs to be pub for macro use). Once `extract_if`
507 /// ([rust#43244](https://github.com/rust-lang/rust/issues/43244))
508 /// is stabilized, we can replace this with a take_children which doesn't
509 /// remove text nodes.
510 #[inline]
511 #[doc(hidden)]
512 pub fn take_contents_as_children(&mut self) -> ContentsAsChildren<'_> {
513 ContentsAsChildren {
514 iter: self.children.drain(..),
515 }
516 }
517
518 /// Returns an iterator over references to every text node of this element.
519 ///
520 /// # Examples
521 ///
522 /// ```rust
523 /// use minidom::Element;
524 ///
525 /// let elem: Element = "<root xmlns=\"ns1\">hello<c /> world!</root>".parse().unwrap();
526 ///
527 /// let mut iter = elem.texts();
528 /// assert_eq!(iter.next().unwrap(), "hello");
529 /// assert_eq!(iter.next().unwrap(), " world!");
530 /// assert_eq!(iter.next(), None);
531 /// ```
532 #[inline]
533 #[must_use]
534 pub fn texts(&self) -> Texts<'_> {
535 Texts {
536 iter: self.children.iter(),
537 }
538 }
539
540 /// Returns an iterator over mutable references to every text node of this element.
541 #[inline]
542 #[must_use]
543 pub fn texts_mut(&mut self) -> TextsMut<'_> {
544 TextsMut {
545 iter: self.children.iter_mut(),
546 }
547 }
548
549 /// Appends a child node to the `Element`, returning the appended node.
550 ///
551 /// # Examples
552 ///
553 /// ```rust
554 /// use minidom::Element;
555 ///
556 /// let mut elem = Element::bare("root", "ns1");
557 ///
558 /// assert_eq!(elem.children().count(), 0);
559 ///
560 /// elem.append_child(Element::bare("child", "ns1"));
561 ///
562 /// {
563 /// let mut iter = elem.children();
564 /// assert_eq!(iter.next().unwrap().name(), "child");
565 /// assert_eq!(iter.next(), None);
566 /// }
567 ///
568 /// let child = elem.append_child(Element::bare("new", "ns1"));
569 ///
570 /// assert_eq!(child.name(), "new");
571 /// ```
572 pub fn append_child(&mut self, child: Element) -> &mut Element {
573 self.children.push(Node::Element(child));
574 if let Node::Element(ref mut cld) = *self.children.last_mut().unwrap() {
575 cld
576 } else {
577 unreachable!()
578 }
579 }
580
581 /// Appends a text node to an `Element`.
582 ///
583 /// # Examples
584 ///
585 /// ```rust
586 /// use minidom::Element;
587 ///
588 /// let mut elem = Element::bare("node", "ns1");
589 ///
590 /// assert_eq!(elem.text(), "");
591 ///
592 /// elem.append_text_node("text");
593 ///
594 /// assert_eq!(elem.text(), "text");
595 /// ```
596 pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
597 self.children.push(Node::Text(child.into()));
598 }
599
600 /// Appends a string as plain text to an `Element`.
601 ///
602 /// If the last child node of the element is a text node, the string will be appended to it.
603 /// Otherwise, a new text node will be created.
604 ///
605 /// # Examples
606 ///
607 /// ```rust
608 /// use minidom::Element;
609 ///
610 /// let mut elem = Element::bare("node", "ns1");
611 ///
612 /// assert_eq!(elem.text(), "");
613 ///
614 /// elem.append_text_node("text");
615 ///
616 /// elem.append_text(" and more text");
617 ///
618 /// assert_eq!(elem.nodes().count(), 1);
619 /// ```
620 pub fn append_text<S: Into<String>>(&mut self, text: S) {
621 if let Some(Node::Text(ref mut child)) = self.children.last_mut() {
622 child.push_str(&text.into());
623 } else {
624 self.append_text_node(text);
625 }
626 }
627
628 /// Appends a node to an `Element`.
629 ///
630 /// # Examples
631 ///
632 /// ```rust
633 /// use minidom::{Element, Node};
634 ///
635 /// let mut elem = Element::bare("node", "ns1");
636 ///
637 /// elem.append_node(Node::Text("hello".to_owned()));
638 ///
639 /// assert_eq!(elem.text(), "hello");
640 /// ```
641 pub fn append_node(&mut self, node: Node) {
642 self.children.push(node);
643 }
644
645 /// Returns the concatenation of all text nodes in the `Element`.
646 ///
647 /// # Examples
648 ///
649 /// ```rust
650 /// use minidom::Element;
651 ///
652 /// let elem: Element = "<node xmlns=\"ns1\">hello,<split /> world!</node>".parse().unwrap();
653 ///
654 /// assert_eq!(elem.text(), "hello, world!");
655 /// ```
656 #[must_use]
657 pub fn text(&self) -> String {
658 self.texts().fold(String::new(), |ret, new| ret + new)
659 }
660
661 /// Returns a reference to the first child element with the specific name and namespace, if it
662 /// exists in the direct descendants of this `Element`, else returns `None`.
663 ///
664 /// # Examples
665 ///
666 /// ```rust
667 /// use minidom::{Element, NSChoice};
668 ///
669 /// let elem: Element = r#"<node xmlns="ns"><a/><a xmlns="other_ns" /><b/></node>"#.parse().unwrap();
670 /// assert!(elem.get_child("a", "ns").unwrap().is("a", "ns"));
671 /// assert!(elem.get_child("a", "other_ns").unwrap().is("a", "other_ns"));
672 /// assert!(elem.get_child("b", "ns").unwrap().is("b", "ns"));
673 /// assert_eq!(elem.get_child("c", "ns"), None);
674 /// assert_eq!(elem.get_child("b", "other_ns"), None);
675 /// assert_eq!(elem.get_child("a", "inexistent_ns"), None);
676 /// ```
677 pub fn get_child<'a, N: AsRef<str>, NS: Into<NSChoice<'a>>>(
678 &self,
679 name: N,
680 namespace: NS,
681 ) -> Option<&Element> {
682 let namespace = namespace.into();
683 for fork in &self.children {
684 if let Node::Element(ref e) = *fork {
685 if e.is(name.as_ref(), namespace) {
686 return Some(e);
687 }
688 }
689 }
690 None
691 }
692
693 /// Returns a mutable reference to the first child element with the specific name and namespace,
694 /// if it exists in the direct descendants of this `Element`, else returns `None`.
695 pub fn get_child_mut<'a, N: AsRef<str>, NS: Into<NSChoice<'a>>>(
696 &mut self,
697 name: N,
698 namespace: NS,
699 ) -> Option<&mut Element> {
700 let namespace = namespace.into();
701 for fork in &mut self.children {
702 if let Node::Element(ref mut e) = *fork {
703 if e.is(name.as_ref(), namespace) {
704 return Some(e);
705 }
706 }
707 }
708 None
709 }
710
711 /// Returns whether a specific child with this name and namespace exists in the direct
712 /// descendants of the `Element`.
713 ///
714 /// # Examples
715 ///
716 /// ```rust
717 /// use minidom::{Element, NSChoice};
718 ///
719 /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
720 /// assert_eq!(elem.has_child("a", "other_ns"), true);
721 /// assert_eq!(elem.has_child("a", "ns"), true);
722 /// assert_eq!(elem.has_child("a", "inexistent_ns"), false);
723 /// assert_eq!(elem.has_child("b", "ns"), true);
724 /// assert_eq!(elem.has_child("b", "other_ns"), false);
725 /// assert_eq!(elem.has_child("b", "inexistent_ns"), false);
726 /// ```
727 pub fn has_child<'a, N: AsRef<str>, NS: Into<NSChoice<'a>>>(
728 &self,
729 name: N,
730 namespace: NS,
731 ) -> bool {
732 self.get_child(name, namespace).is_some()
733 }
734
735 /// Removes the first child with this name and namespace, if it exists, and returns an
736 /// `Option<Element>` containing this child if it succeeds.
737 /// Returns `None` if no child matches this name and namespace.
738 ///
739 /// # Examples
740 ///
741 /// ```rust
742 /// use minidom::{Element, NSChoice};
743 ///
744 /// let mut elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
745 /// assert!(elem.remove_child("a", "ns").unwrap().is("a", "ns"));
746 /// assert!(elem.remove_child("a", "ns").is_none());
747 /// assert!(elem.remove_child("inexistent", "inexistent").is_none());
748 /// ```
749 pub fn remove_child<'a, N: AsRef<str>, NS: Into<NSChoice<'a>>>(
750 &mut self,
751 name: N,
752 namespace: NS,
753 ) -> Option<Element> {
754 let name = name.as_ref();
755 let namespace = namespace.into();
756 let idx = self.children.iter().position(|x| {
757 if let Node::Element(ref elm) = x {
758 elm.is(name, namespace)
759 } else {
760 false
761 }
762 })?;
763 self.children.remove(idx).into_element()
764 }
765
766 /// Remove the leading nodes up to the first child element and
767 /// return it
768 pub fn unshift_child(&mut self) -> Option<Element> {
769 while !self.children.is_empty() {
770 if let Some(el) = self.children.remove(0).into_element() {
771 return Some(el);
772 }
773 }
774
775 None
776 }
777}
778
779/// An iterator over references to child elements of an `Element`.
780pub struct Children<'a> {
781 iter: slice::Iter<'a, Node>,
782}
783
784impl<'a> Iterator for Children<'a> {
785 type Item = &'a Element;
786
787 fn next(&mut self) -> Option<&'a Element> {
788 for item in &mut self.iter {
789 if let Node::Element(ref child) = *item {
790 return Some(child);
791 }
792 }
793 None
794 }
795}
796
797/// An iterator over mutable references to child elements of an `Element`.
798pub struct ChildrenMut<'a> {
799 iter: slice::IterMut<'a, Node>,
800}
801
802impl<'a> Iterator for ChildrenMut<'a> {
803 type Item = &'a mut Element;
804
805 fn next(&mut self) -> Option<&'a mut Element> {
806 for item in &mut self.iter {
807 if let Node::Element(ref mut child) = *item {
808 return Some(child);
809 }
810 }
811 None
812 }
813}
814
815/// An iterator over references to child elements of an `Element`.
816pub struct ContentsAsChildren<'a> {
817 iter: alloc::vec::Drain<'a, Node>,
818}
819
820impl Iterator for ContentsAsChildren<'_> {
821 type Item = Element;
822
823 fn next(&mut self) -> Option<Element> {
824 for item in &mut self.iter {
825 if let Node::Element(child) = item {
826 return Some(child);
827 }
828 }
829 None
830 }
831}
832
833/// An iterator over references to child text nodes of an `Element`.
834pub struct Texts<'a> {
835 iter: slice::Iter<'a, Node>,
836}
837
838impl<'a> Iterator for Texts<'a> {
839 type Item = &'a str;
840
841 fn next(&mut self) -> Option<&'a str> {
842 for item in &mut self.iter {
843 if let Node::Text(ref child) = *item {
844 return Some(child);
845 }
846 }
847 None
848 }
849}
850
851/// An iterator over mutable references to child text nodes of an `Element`.
852pub struct TextsMut<'a> {
853 iter: slice::IterMut<'a, Node>,
854}
855
856impl<'a> Iterator for TextsMut<'a> {
857 type Item = &'a mut String;
858
859 fn next(&mut self) -> Option<&'a mut String> {
860 for item in &mut self.iter {
861 if let Node::Text(ref mut child) = *item {
862 return Some(child);
863 }
864 }
865 None
866 }
867}
868
869/// An iterator over references to all child nodes of an `Element`.
870pub type Nodes<'a> = slice::Iter<'a, Node>;
871
872/// An iterator over mutable references to all child nodes of an `Element`.
873pub type NodesMut<'a> = slice::IterMut<'a, Node>;
874
875/// An iterator over the attributes of an `Element`.
876pub struct Attrs<'a> {
877 iter: btree_map::Iter<'a, String, String>,
878}
879
880impl<'a> Iterator for Attrs<'a> {
881 type Item = (&'a str, &'a str);
882
883 fn next(&mut self) -> Option<Self::Item> {
884 self.iter.next().map(|(x, y)| (x.as_ref(), y.as_ref()))
885 }
886}
887
888/// An iterator over the attributes of an `Element`, with the values mutable.
889pub struct AttrsMut<'a> {
890 iter: btree_map::IterMut<'a, String, String>,
891}
892
893impl<'a> Iterator for AttrsMut<'a> {
894 type Item = (&'a str, &'a mut String);
895
896 fn next(&mut self) -> Option<Self::Item> {
897 self.iter.next().map(|(x, y)| (x.as_ref(), y))
898 }
899}
900
901/// A builder for `Element`s.
902pub struct ElementBuilder {
903 root: Element,
904}
905
906impl ElementBuilder {
907 /// Sets a custom prefix. It is not possible to set the same prefix twice.
908 pub fn prefix<S: Into<Namespace>>(
909 mut self,
910 prefix: Prefix,
911 namespace: S,
912 ) -> Result<ElementBuilder> {
913 if self.root.prefixes.get(&prefix).is_some() {
914 return Err(Error::DuplicatePrefix);
915 }
916 self.root.prefixes.insert(prefix, namespace.into());
917 Ok(self)
918 }
919
920 /// Sets an attribute.
921 #[must_use]
922 pub fn attr<S: Into<String>, V: IntoAttributeValue>(
923 mut self,
924 name: S,
925 value: V,
926 ) -> ElementBuilder {
927 self.root.set_attr(name, value);
928 self
929 }
930
931 /// Appends anything implementing `Into<Node>` into the tree.
932 #[must_use]
933 pub fn append<T: Into<Node>>(mut self, node: T) -> ElementBuilder {
934 self.root.append_node(node.into());
935 self
936 }
937
938 /// Appends an iterator of things implementing `Into<Node>` into the tree.
939 #[must_use]
940 pub fn append_all<T: Into<Node>, I: IntoIterator<Item = T>>(
941 mut self,
942 iter: I,
943 ) -> ElementBuilder {
944 for node in iter {
945 self.root.append_node(node.into());
946 }
947 self
948 }
949
950 /// Builds the `Element`.
951 #[must_use]
952 pub fn build(self) -> Element {
953 self.root
954 }
955}
956
957#[cfg(test)]
958mod tests {
959 use super::*;
960
961 #[test]
962 fn test_element_new() {
963 let elem = Element::new(
964 "name".to_owned(),
965 "namespace".to_owned(),
966 (None, "namespace".to_owned()),
967 BTreeMap::from_iter([("name".to_string(), "value".to_string())].into_iter()),
968 Vec::new(),
969 );
970
971 assert_eq!(elem.name(), "name");
972 assert_eq!(elem.ns(), "namespace".to_owned());
973 assert_eq!(elem.attr("name"), Some("value"));
974 assert_eq!(elem.attr("inexistent"), None);
975 }
976
977 #[test]
978 fn test_from_reader_simple() {
979 let xml = b"<foo xmlns='ns1'></foo>";
980 let elem = Element::from_reader(&xml[..]);
981
982 let elem2 = Element::builder("foo", "ns1").build();
983
984 assert_eq!(elem.unwrap(), elem2);
985 }
986
987 #[test]
988 fn test_from_reader_nested() {
989 let xml = b"<foo xmlns='ns1'><bar xmlns='ns1' baz='qxx' /></foo>";
990 let elem = Element::from_reader(&xml[..]);
991
992 let nested = Element::builder("bar", "ns1").attr("baz", "qxx").build();
993 let elem2 = Element::builder("foo", "ns1").append(nested).build();
994
995 assert_eq!(elem.unwrap(), elem2);
996 }
997
998 #[test]
999 fn test_from_reader_with_prefix() {
1000 let xml = b"<foo xmlns='ns1'><prefix:bar xmlns:prefix='ns1' baz='qxx' /></foo>";
1001 let elem = Element::from_reader(&xml[..]);
1002
1003 let nested = Element::builder("bar", "ns1").attr("baz", "qxx").build();
1004 let elem2 = Element::builder("foo", "ns1").append(nested).build();
1005
1006 assert_eq!(elem.unwrap(), elem2);
1007 }
1008
1009 #[test]
1010 fn test_from_reader_split_prefix() {
1011 let xml = b"<foo:bar xmlns:foo='ns1'/>";
1012 let elem = Element::from_reader(&xml[..]).unwrap();
1013
1014 assert_eq!(elem.name(), String::from("bar"));
1015 assert_eq!(elem.ns(), String::from("ns1"));
1016 // Ensure the prefix is properly added to the store
1017 assert_eq!(
1018 elem.prefixes.get(&Some(String::from("foo"))),
1019 Some(&String::from("ns1"))
1020 );
1021 }
1022
1023 #[test]
1024 fn parses_spectest_xml() {
1025 // From: https://gitlab.com/lumi/minidom-rs/issues/8
1026 let xml = br#"<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0">
1027 <rng:name xmlns:rng="http://relaxng.org/ns/structure/1.0"></rng:name>
1028 </rng:grammar>
1029 "#;
1030 let _ = Element::from_reader(&xml[..]).unwrap();
1031 }
1032
1033 #[test]
1034 fn does_not_unescape_cdata() {
1035 let xml = b"<test xmlns='test'><![CDATA['>blah<blah>]]></test>";
1036 let elem = Element::from_reader(&xml[..]).unwrap();
1037 assert_eq!(elem.text(), "'>blah<blah>");
1038 }
1039
1040 #[test]
1041 fn test_compare_all_ns() {
1042 let xml = b"<foo xmlns='foo' xmlns:bar='baz'><bar:meh xmlns:bar='baz' /></foo>";
1043 let elem = Element::from_reader(&xml[..]).unwrap();
1044
1045 let elem2 = elem.clone();
1046
1047 let xml3 = b"<foo xmlns='foo'><bar:meh xmlns:bar='baz'/></foo>";
1048 let elem3 = Element::from_reader(&xml3[..]).unwrap();
1049
1050 let xml4 = b"<prefix:foo xmlns:prefix='foo'><bar:meh xmlns:bar='baz'/></prefix:foo>";
1051 let elem4 = Element::from_reader(&xml4[..]).unwrap();
1052
1053 assert_eq!(elem, elem2);
1054 assert_eq!(elem, elem3);
1055 assert_eq!(elem, elem4);
1056 }
1057
1058 #[test]
1059 fn test_compare_empty_children() {
1060 let elem1 = Element::bare("p", "");
1061 let elem2 = Element::builder("p", "")
1062 .append(Node::Element(Element::bare("span", "")))
1063 .build();
1064
1065 assert_ne!(elem1, elem2);
1066 }
1067
1068 #[test]
1069 fn test_from_reader_with_prefixes() {
1070 let xml = b"<foo><bar xmlns='baz'/></foo>";
1071 let elem =
1072 Element::from_reader_with_prefixes(&xml[..], String::from("jabber:client")).unwrap();
1073
1074 let xml2 = b"<foo xmlns='jabber:client'><bar xmlns='baz'/></foo>";
1075 let elem2 = Element::from_reader(&xml2[..]).unwrap();
1076
1077 assert_eq!(elem, elem2);
1078 }
1079
1080 #[test]
1081 fn failure_with_duplicate_namespace() {
1082 let _: Element = r###"<?xml version="1.0" encoding="UTF-8"?>
1083 <wsdl:definitions
1084 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
1085 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
1086 <wsdl:types>
1087 <xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
1088 </xsd:schema>
1089 </wsdl:types>
1090 </wsdl:definitions>
1091 "###
1092 .parse()
1093 .unwrap();
1094 }
1095}