1//! Provides an `Element` type, which represents DOM nodes, and a builder to create them with.
2
3use std::io:: Write;
4use std::collections::{btree_map, BTreeMap};
5
6use std::str;
7
8use error::{Error, ErrorKind, Result};
9
10use quick_xml::reader::Reader as EventReader;
11use quick_xml::events::{Event, BytesStart};
12
13use std::io::BufRead;
14
15use std::str::FromStr;
16
17use std::slice;
18
19use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
20
21/// A node in an element tree.
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub enum Node {
24 /// An `Element`.
25 Element(Element),
26 /// A text node.
27 Text(String),
28}
29
30impl Node {
31 /// Turns this into an `Element` if possible, else returns None.
32 ///
33 /// # Examples
34 ///
35 /// ```rust
36 /// use minidom::Node;
37 ///
38 /// let elm = Node::Element("<meow />".parse().unwrap());
39 /// let txt = Node::Text("meow".to_owned());
40 ///
41 /// assert_eq!(elm.as_element().unwrap().name(), "meow");
42 /// assert_eq!(txt.as_element(), None);
43 /// ```
44 pub fn as_element(&self) -> Option<&Element> {
45 match *self {
46 Node::Element(ref e) => Some(e),
47 Node::Text(_) => None,
48 }
49 }
50
51 /// Turns this into a `String` if possible, else returns None.
52 ///
53 /// # Examples
54 ///
55 /// ```rust
56 /// use minidom::Node;
57 ///
58 /// let elm = Node::Element("<meow />".parse().unwrap());
59 /// let txt = Node::Text("meow".to_owned());
60 ///
61 /// assert_eq!(elm.as_text(), None);
62 /// assert_eq!(txt.as_text().unwrap(), "meow");
63 /// ```
64 pub fn as_text(&self) -> Option<&str> {
65 match *self {
66 Node::Element(_) => None,
67 Node::Text(ref s) => Some(s),
68 }
69 }
70
71 fn write_to_inner<W: Write>(&self, writer: &mut W, last_namespace: &mut Option<String>) -> Result<()>{
72 match *self {
73 Node::Element(ref elmt) => elmt.write_to_inner(writer, last_namespace)?,
74 Node::Text(ref s) => write!(writer, "{}", s)?,
75 }
76
77 Ok(())
78 }
79}
80
81#[derive(Clone, PartialEq, Eq, Debug)]
82/// A struct representing a DOM Element.
83pub struct Element {
84 name: String,
85 namespace: Option<String>,
86 attributes: BTreeMap<String, String>,
87 children: Vec<Node>,
88}
89
90impl<'a> From<&'a Element> for String {
91 fn from(elem: &'a Element) -> String {
92 let mut writer = Vec::new();
93 elem.write_to(&mut writer).unwrap();
94 String::from_utf8(writer).unwrap()
95 }
96}
97
98
99impl FromStr for Element {
100 type Err = Error;
101
102 fn from_str(s: &str) -> Result<Element> {
103 let mut reader = EventReader::from_str(s);
104 Element::from_reader(&mut reader)
105 }
106}
107
108impl Element {
109 fn new(name: String, namespace: Option<String>, attributes: BTreeMap<String, String>, children: Vec<Node>) -> Element {
110 Element {
111 name: name,
112 namespace: namespace,
113 attributes: attributes,
114 children: children,
115 }
116 }
117
118 /// Return a builder for an `Element` with the given `name`.
119 ///
120 /// # Examples
121 ///
122 /// ```rust
123 /// use minidom::Element;
124 ///
125 /// let elem = Element::builder("name")
126 /// .ns("namespace")
127 /// .attr("name", "value")
128 /// .append("inner")
129 /// .build();
130 ///
131 /// assert_eq!(elem.name(), "name");
132 /// assert_eq!(elem.ns(), Some("namespace"));
133 /// assert_eq!(elem.attr("name"), Some("value"));
134 /// assert_eq!(elem.attr("inexistent"), None);
135 /// assert_eq!(elem.text(), "inner");
136 /// ```
137 pub fn builder<S: Into<String>>(name: S) -> ElementBuilder {
138 ElementBuilder {
139 root: Element::new(name.into(), None, BTreeMap::new(), Vec::new()),
140 }
141 }
142
143 /// Returns a bare minimum `Element` with this name.
144 ///
145 /// # Examples
146 ///
147 /// ```rust
148 /// use minidom::Element;
149 ///
150 /// let bare = Element::bare("name");
151 ///
152 /// assert_eq!(bare.name(), "name");
153 /// assert_eq!(bare.ns(), None);
154 /// assert_eq!(bare.attr("name"), None);
155 /// assert_eq!(bare.text(), "");
156 /// ```
157 pub fn bare<S: Into<String>>(name: S) -> Element {
158 Element {
159 name: name.into(),
160 namespace: None,
161 attributes: BTreeMap::new(),
162 children: Vec::new(),
163 }
164 }
165
166 /// Returns a reference to the name of this element.
167 pub fn name(&self) -> &str {
168 &self.name
169 }
170
171 /// Returns a reference to the namespace of this element, if it has one, else `None`.
172 pub fn ns(&self) -> Option<&str> {
173 self.namespace.as_ref()
174 .map(String::as_ref)
175 }
176
177 /// Returns a reference to the value of the given attribute, if it exists, else `None`.
178 pub fn attr(&self, name: &str) -> Option<&str> {
179 if let Some(value) = self.attributes.get(name) {
180 return Some(value)
181 }
182 None
183 }
184
185 /// Returns an iterator over the attributes of this element.
186 ///
187 /// # Example
188 ///
189 /// ```rust
190 /// use minidom::Element;
191 ///
192 /// let elm: Element = "<elem a=\"b\" />".parse().unwrap();
193 ///
194 /// let mut iter = elm.attrs();
195 ///
196 /// assert_eq!(iter.next().unwrap(), ("a", "b"));
197 /// assert_eq!(iter.next(), None);
198 /// ```
199 pub fn attrs(&self) -> Attrs {
200 Attrs {
201 iter: self.attributes.iter(),
202 }
203 }
204
205 /// Returns an iterator over the attributes of this element, with the value being a mutable
206 /// reference.
207 pub fn attrs_mut(&mut self) -> AttrsMut {
208 AttrsMut {
209 iter: self.attributes.iter_mut(),
210 }
211 }
212
213 /// Modifies the value of an attribute.
214 pub fn set_attr<S: Into<String>, V: IntoAttributeValue>(&mut self, name: S, val: V) {
215 let name = name.into();
216 let val = val.into_attribute_value();
217
218 if let Some(value) = self.attributes.get_mut(&name) {
219 *value = val.expect("removing existing value via set_attr, this is not yet supported (TODO)"); // TODO
220 return;
221 }
222
223 if let Some(val) = val {
224 self.attributes.insert(name, val);
225 }
226 }
227
228 /// Returns whether the element has the given name and namespace.
229 ///
230 /// # Examples
231 ///
232 /// ```rust
233 /// use minidom::Element;
234 ///
235 /// let elem = Element::builder("name").ns("namespace").build();
236 ///
237 /// assert_eq!(elem.is("name", "namespace"), true);
238 /// assert_eq!(elem.is("name", "wrong"), false);
239 /// assert_eq!(elem.is("wrong", "namespace"), false);
240 /// assert_eq!(elem.is("wrong", "wrong"), false);
241 /// ```
242 pub fn is<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
243 let ns = self.namespace.as_ref().map(String::as_ref);
244 self.name == name.as_ref() && ns == Some(namespace.as_ref())
245 }
246
247 /// Parse a document from an `EventReader`.
248 pub fn from_reader<R: BufRead>(reader: &mut EventReader<R>) -> Result<Element> {
249 let mut buf = Vec::new();
250 let root: Element;
251
252 loop {
253 let e = reader.read_event(&mut buf)?;
254 match e {
255 Event::Empty(ref e) | Event::Start(ref e) => {
256 root = build_element(e)?; // FIXME: could be break build_element(e)? when break value is stable
257 break;
258 },
259 Event::Eof => {
260 bail!(ErrorKind::EndOfDocument);
261 },
262 _ => () // TODO: may need more errors
263 }
264 };
265
266 let mut stack = vec![root];
267
268 loop {
269 match reader.read_event(&mut buf)? {
270 Event::Empty(ref e) => {
271 let elem = build_element(e)?;
272 // Since there is no Event::End after, directly append it to the current node
273 stack.last_mut().unwrap().append_child(elem);
274 },
275 Event::Start(ref e) => {
276 let elem = build_element(e)?;
277 stack.push(elem);
278 },
279 Event::End(ref e) => {
280 if stack.len() <= 1 {
281 break;
282 }
283 let elem = stack.pop().unwrap();
284 if let Some(to) = stack.last_mut() {
285 if elem.name().as_bytes() != e.name() {
286 bail!(ErrorKind::InvalidElementClosed);
287 }
288 to.append_child(elem);
289 }
290 },
291 Event::Text(s) | Event::CData(s) => {
292 let text = s.unescape_and_decode(reader)?;
293 if text != "" {
294 let mut current_elem = stack.last_mut().unwrap();
295 current_elem.append_text_node(text);
296 }
297 },
298 Event::Eof => {
299 break;
300 },
301 _ => (), // TODO: may need to implement more
302 }
303 }
304 Ok(stack.pop().unwrap())
305 }
306
307 /// Output a document to a `Writer`.
308 pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
309 let mut last_namespace = None;
310 write!(writer, "<?xml version=\"1.0\" encoding=\"utf-8\"?>")?;
311 self.write_to_inner(writer, &mut last_namespace)
312 }
313
314 /// Output a document to a `Writer` assuming you're already in the provided namespace
315 pub fn write_to_in_namespace<W: Write>(&self, writer: &mut W, namespace: &str) -> Result<()> {
316 write!(writer, "<?xml version=\"1.0\" encoding=\"utf-8\"?>")?;
317 self.write_to_inner(writer, &mut Some(namespace.to_owned()))
318 }
319
320 fn write_to_inner<W: Write>(&self, writer: &mut W, last_namespace: &mut Option<String>) -> Result<()> {
321 write!(writer, "<")?;
322 write!(writer, "{}", self.name)?;
323
324 if let Some(ref ns) = self.namespace {
325 if *last_namespace != self.namespace {
326 write!(writer, " xmlns=\"{}\"", ns)?;
327 *last_namespace = Some(ns.clone());
328 }
329 }
330
331 for (key, value) in &self.attributes {
332 write!(writer, " {}=\"{}\"", key, value)?;
333 }
334
335 if self.children.is_empty() {
336 write!(writer, " />")?;
337 return Ok(())
338 }
339
340 write!(writer, ">")?;
341
342 for child in &self.children {
343 child.write_to_inner(writer, last_namespace)?;
344 }
345
346 write!(writer, "</{}>", self.name)?;
347 Ok(())
348 }
349
350 /// Returns an iterator over references to every child node of this element.
351 ///
352 /// # Examples
353 ///
354 /// ```rust
355 /// use minidom::Element;
356 ///
357 /// let elem: Element = "<root>a<c1 />b<c2 />c</root>".parse().unwrap();
358 ///
359 /// let mut iter = elem.nodes();
360 ///
361 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "a");
362 /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c1");
363 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "b");
364 /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c2");
365 /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "c");
366 /// assert_eq!(iter.next(), None);
367 /// ```
368 #[inline] pub fn nodes(&self) -> Nodes {
369 self.children.iter()
370 }
371
372 /// Returns an iterator over mutable references to every child node of this element.
373 #[inline] pub fn nodes_mut(&mut self) -> NodesMut {
374 self.children.iter_mut()
375 }
376
377 /// Returns an iterator over references to every child element of this element.
378 ///
379 /// # Examples
380 ///
381 /// ```rust
382 /// use minidom::Element;
383 ///
384 /// let elem: Element = "<root>hello<child1 />this<child2 />is<child3 />ignored</root>".parse().unwrap();
385 ///
386 /// let mut iter = elem.children();
387 /// assert_eq!(iter.next().unwrap().name(), "child1");
388 /// assert_eq!(iter.next().unwrap().name(), "child2");
389 /// assert_eq!(iter.next().unwrap().name(), "child3");
390 /// assert_eq!(iter.next(), None);
391 /// ```
392 #[inline] pub fn children(&self) -> Children {
393 Children {
394 iter: self.children.iter(),
395 }
396 }
397
398 /// Returns an iterator over mutable references to every child element of this element.
399 #[inline] pub fn children_mut(&mut self) -> ChildrenMut {
400 ChildrenMut {
401 iter: self.children.iter_mut(),
402 }
403 }
404
405 /// Returns an iterator over references to every text node of this element.
406 ///
407 /// # Examples
408 ///
409 /// ```rust
410 /// use minidom::Element;
411 ///
412 /// let elem: Element = "<root>hello<c /> world!</root>".parse().unwrap();
413 ///
414 /// let mut iter = elem.texts();
415 /// assert_eq!(iter.next().unwrap(), "hello");
416 /// assert_eq!(iter.next().unwrap(), " world!");
417 /// assert_eq!(iter.next(), None);
418 /// ```
419 #[inline] pub fn texts(&self) -> Texts {
420 Texts {
421 iter: self.children.iter(),
422 }
423 }
424
425 /// Returns an iterator over mutable references to every text node of this element.
426 #[inline] pub fn texts_mut(&mut self) -> TextsMut {
427 TextsMut {
428 iter: self.children.iter_mut(),
429 }
430 }
431
432 /// Appends a child node to the `Element`, returning the appended node.
433 ///
434 /// # Examples
435 ///
436 /// ```rust
437 /// use minidom::Element;
438 ///
439 /// let mut elem = Element::bare("root");
440 ///
441 /// assert_eq!(elem.children().count(), 0);
442 ///
443 /// elem.append_child(Element::bare("child"));
444 ///
445 /// {
446 /// let mut iter = elem.children();
447 /// assert_eq!(iter.next().unwrap().name(), "child");
448 /// assert_eq!(iter.next(), None);
449 /// }
450 ///
451 /// let child = elem.append_child(Element::bare("new"));
452 ///
453 /// assert_eq!(child.name(), "new");
454 /// ```
455 pub fn append_child(&mut self, mut child: Element) -> &mut Element {
456 if child.namespace.is_none() && self.namespace.is_some() {
457 child.namespace = self.namespace.clone();
458 child.propagate_namespaces();
459 }
460 self.children.push(Node::Element(child));
461 if let Node::Element(ref mut cld) = *self.children.last_mut().unwrap() {
462 cld
463 }
464 else {
465 unreachable!()
466 }
467 }
468
469 fn propagate_namespaces(&mut self) {
470 let ns = self.namespace.clone();
471 for child in self.children_mut() {
472 if child.namespace.is_none() {
473 child.namespace = ns.clone();
474 child.propagate_namespaces();
475 }
476 }
477 }
478
479 /// Appends a text node to an `Element`.
480 ///
481 /// # Examples
482 ///
483 /// ```rust
484 /// use minidom::Element;
485 ///
486 /// let mut elem = Element::bare("node");
487 ///
488 /// assert_eq!(elem.text(), "");
489 ///
490 /// elem.append_text_node("text");
491 ///
492 /// assert_eq!(elem.text(), "text");
493 /// ```
494 pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
495 self.children.push(Node::Text(child.into()));
496 }
497
498 /// Appends a node to an `Element`.
499 ///
500 /// # Examples
501 ///
502 /// ```rust
503 /// use minidom::{Element, Node};
504 ///
505 /// let mut elem = Element::bare("node");
506 ///
507 /// elem.append_node(Node::Text("hello".to_owned()));
508 ///
509 /// assert_eq!(elem.text(), "hello");
510 /// ```
511 pub fn append_node(&mut self, node: Node) {
512 self.children.push(node);
513 }
514
515 /// Returns the concatenation of all text nodes in the `Element`.
516 ///
517 /// # Examples
518 ///
519 /// ```rust
520 /// use minidom::Element;
521 ///
522 /// let elem: Element = "<node>hello,<split /> world!</node>".parse().unwrap();
523 ///
524 /// assert_eq!(elem.text(), "hello, world!");
525 /// ```
526 pub fn text(&self) -> String {
527 self.texts().fold(String::new(), |ret, new| ret + new)
528 }
529
530 /// Returns a reference to the first child element with the specific name and namespace, if it
531 /// exists in the direct descendants of this `Element`, else returns `None`.
532 ///
533 /// # Examples
534 ///
535 /// ```rust
536 /// use minidom::Element;
537 ///
538 /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
539 ///
540 /// assert!(elem.get_child("a", "ns").unwrap().is("a", "ns"));
541 /// assert!(elem.get_child("a", "other_ns").unwrap().is("a", "other_ns"));
542 /// assert!(elem.get_child("b", "ns").unwrap().is("b", "ns"));
543 /// assert_eq!(elem.get_child("c", "ns"), None);
544 /// assert_eq!(elem.get_child("b", "other_ns"), None);
545 /// assert_eq!(elem.get_child("a", "inexistent_ns"), None);
546 /// ```
547 pub fn get_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> Option<&Element> {
548 for fork in &self.children {
549 if let Node::Element(ref e) = *fork {
550 if e.is(name.as_ref(), namespace.as_ref()) {
551 return Some(e);
552 }
553 }
554 }
555 None
556 }
557
558 /// Returns a mutable reference to the first child element with the specific name and namespace,
559 /// if it exists in the direct descendants of this `Element`, else returns `None`.
560 pub fn get_child_mut<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<&mut Element> {
561 for fork in &mut self.children {
562 if let Node::Element(ref mut e) = *fork {
563 if e.is(name.as_ref(), namespace.as_ref()) {
564 return Some(e);
565 }
566 }
567 }
568 None
569 }
570
571 /// Returns whether a specific child with this name and namespace exists in the direct
572 /// descendants of the `Element`.
573 ///
574 /// # Examples
575 ///
576 /// ```rust
577 /// use minidom::Element;
578 ///
579 /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
580 ///
581 /// assert_eq!(elem.has_child("a", "other_ns"), true);
582 /// assert_eq!(elem.has_child("a", "ns"), true);
583 /// assert_eq!(elem.has_child("a", "inexistent_ns"), false);
584 /// assert_eq!(elem.has_child("b", "ns"), true);
585 /// assert_eq!(elem.has_child("b", "other_ns"), false);
586 /// assert_eq!(elem.has_child("b", "inexistent_ns"), false);
587 /// ```
588 pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
589 self.get_child(name, namespace).is_some()
590 }
591}
592
593fn build_element(event: &BytesStart) -> Result<Element> {
594 let mut attributes = event.attributes()
595 .map(|o| {
596 let o = o?;
597 let key = str::from_utf8(o.key)?.to_owned();
598 let value = str::from_utf8(o.value)?.to_owned();
599 Ok((key, value))
600 }
601 )
602 .collect::<Result<BTreeMap<String, String>>>()?;
603 let mut ns_key = None;
604 for (key, _) in &attributes {
605 if key == "xmlns" || key.starts_with("xmlns:") {
606 ns_key = Some(key.clone());
607 }
608 }
609
610 let ns = match ns_key {
611 None => None,
612 Some(key) => attributes.remove(&key),
613 };
614 let name = str::from_utf8(event.name())?.to_owned();
615 Ok(Element::new(name, ns, attributes, Vec::new()))
616}
617
618/// An iterator over references to child elements of an `Element`.
619pub struct Children<'a> {
620 iter: slice::Iter<'a, Node>,
621}
622
623impl<'a> Iterator for Children<'a> {
624 type Item = &'a Element;
625
626 fn next(&mut self) -> Option<&'a Element> {
627 for item in &mut self.iter {
628 if let Node::Element(ref child) = *item {
629 return Some(child);
630 }
631 }
632 None
633 }
634}
635
636/// An iterator over mutable references to child elements of an `Element`.
637pub struct ChildrenMut<'a> {
638 iter: slice::IterMut<'a, Node>,
639}
640
641impl<'a> Iterator for ChildrenMut<'a> {
642 type Item = &'a mut Element;
643
644 fn next(&mut self) -> Option<&'a mut Element> {
645 for item in &mut self.iter {
646 if let Node::Element(ref mut child) = *item {
647 return Some(child);
648 }
649 }
650 None
651 }
652}
653
654/// An iterator over references to child text nodes of an `Element`.
655pub struct Texts<'a> {
656 iter: slice::Iter<'a, Node>,
657}
658
659impl<'a> Iterator for Texts<'a> {
660 type Item = &'a str;
661
662 fn next(&mut self) -> Option<&'a str> {
663 for item in &mut self.iter {
664 if let Node::Text(ref child) = *item {
665 return Some(child);
666 }
667 }
668 None
669 }
670}
671
672/// An iterator over mutable references to child text nodes of an `Element`.
673pub struct TextsMut<'a> {
674 iter: slice::IterMut<'a, Node>,
675}
676
677impl<'a> Iterator for TextsMut<'a> {
678 type Item = &'a mut String;
679
680 fn next(&mut self) -> Option<&'a mut String> {
681 for item in &mut self.iter {
682 if let Node::Text(ref mut child) = *item {
683 return Some(child);
684 }
685 }
686 None
687 }
688}
689
690/// An iterator over references to all child nodes of an `Element`.
691pub type Nodes<'a> = slice::Iter<'a, Node>;
692
693/// An iterator over mutable references to all child nodes of an `Element`.
694pub type NodesMut<'a> = slice::IterMut<'a, Node>;
695
696/// An iterator over the attributes of an `Element`.
697pub struct Attrs<'a> {
698 iter: btree_map::Iter<'a, String, String>,
699}
700
701impl<'a> Iterator for Attrs<'a> {
702 type Item = (&'a str, &'a str);
703
704 fn next(&mut self) -> Option<Self::Item> {
705 self.iter.next().map(|(x, y)| (x.as_ref(), y.as_ref()))
706 }
707}
708
709/// An iterator over the attributes of an `Element`, with the values mutable.
710pub struct AttrsMut<'a> {
711 iter: btree_map::IterMut<'a, String, String>,
712}
713
714impl<'a> Iterator for AttrsMut<'a> {
715 type Item = (&'a str, &'a mut String);
716
717 fn next(&mut self) -> Option<Self::Item> {
718 self.iter.next().map(|(x, y)| (x.as_ref(), y))
719 }
720}
721
722/// A builder for `Element`s.
723pub struct ElementBuilder {
724 root: Element,
725}
726
727impl ElementBuilder {
728 /// Sets the namespace.
729 pub fn ns<S: Into<String>>(mut self, namespace: S) -> ElementBuilder {
730 self.root.namespace = Some(namespace.into());
731 self
732 }
733
734 /// Sets an attribute.
735 pub fn attr<S: Into<String>, V: IntoAttributeValue>(mut self, name: S, value: V) -> ElementBuilder {
736 self.root.set_attr(name, value);
737 self
738 }
739
740 /// Appends anything implementing `IntoElements` into the tree.
741 pub fn append<T: IntoElements>(mut self, into: T) -> ElementBuilder {
742 {
743 let mut emitter = ElementEmitter::new(&mut self.root);
744 into.into_elements(&mut emitter);
745 }
746 self
747 }
748
749 /// Builds the `Element`.
750 pub fn build(self) -> Element {
751 self.root
752 }
753}
754
755#[test]
756fn test_element_new() {
757 use std::iter::FromIterator;
758
759 let elem = Element::new( "name".to_owned()
760 , Some("namespace".to_owned())
761 , BTreeMap::from_iter(vec![ ("name".to_string(), "value".to_string()) ].into_iter() )
762 , Vec::new() );
763
764 assert_eq!(elem.name(), "name");
765 assert_eq!(elem.ns(), Some("namespace"));
766 assert_eq!(elem.attr("name"), Some("value"));
767 assert_eq!(elem.attr("inexistent"), None);
768}