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