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