xml/
element.rs

1// RustyXML
2// Copyright 2013-2016 RustyXML developers
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use crate::element_builder::{BuilderError, ElementBuilder};
11use crate::parser::Parser;
12use crate::{escape, AttrMap, Xml};
13
14use std::collections::HashMap;
15use std::fmt;
16use std::iter::IntoIterator;
17use std::slice;
18use std::str::FromStr;
19
20#[derive(Clone, PartialEq, Debug)]
21/// A struct representing an XML element
22pub struct Element {
23    /// The element's name
24    pub name: String,
25    /// The element's namespace
26    pub ns: Option<String>,
27    /// The element's attributes
28    pub attributes: AttrMap<(String, Option<String>), String>,
29    /// The element's child `Xml` nodes
30    pub children: Vec<Xml>,
31    /// The prefixes set for known namespaces
32    pub(crate) prefixes: HashMap<String, String>,
33    /// The element's default namespace
34    pub(crate) default_ns: Option<String>,
35}
36
37fn fmt_elem(
38    elem: &Element,
39    parent: Option<&Element>,
40    all_prefixes: &HashMap<String, String>,
41    f: &mut fmt::Formatter,
42) -> fmt::Result {
43    let mut all_prefixes = all_prefixes.clone();
44    all_prefixes.extend(elem.prefixes.clone().into_iter());
45
46    // Do we need a prefix?
47    if elem.ns != elem.default_ns {
48        let prefix = all_prefixes
49            .get(elem.ns.as_ref().map_or("", |x| &x[..]))
50            .expect("No namespace prefix bound");
51        write!(f, "<{}:{}", *prefix, elem.name)?;
52    } else {
53        write!(f, "<{}", elem.name)?;
54    }
55
56    // Do we need to set the default namespace ?
57    if !elem
58        .attributes
59        .iter()
60        .any(|(&(ref name, _), _)| name == "xmlns")
61    {
62        match (parent, &elem.default_ns) {
63            // No parent, namespace is not empty
64            (None, &Some(ref ns)) => write!(f, " xmlns='{}'", *ns)?,
65            // Parent and child namespace differ
66            (Some(parent), ns) if parent.default_ns != *ns => {
67                write!(f, " xmlns='{}'", ns.as_ref().map_or("", |x| &x[..]))?
68            }
69            _ => (),
70        }
71    }
72
73    for (&(ref name, ref ns), value) in &elem.attributes {
74        match *ns {
75            Some(ref ns) => {
76                let prefix = all_prefixes.get(ns).expect("No namespace prefix bound");
77                write!(f, " {}:{}='{}'", *prefix, name, escape(value))?
78            }
79            None => write!(f, " {}='{}'", name, escape(value))?,
80        }
81    }
82
83    if elem.children.is_empty() {
84        write!(f, "/>")?;
85    } else {
86        write!(f, ">")?;
87        for child in &elem.children {
88            match *child {
89                Xml::ElementNode(ref child) => fmt_elem(child, Some(elem), &all_prefixes, f)?,
90                ref o => fmt::Display::fmt(o, f)?,
91            }
92        }
93        if elem.ns != elem.default_ns {
94            let prefix = all_prefixes
95                .get(elem.ns.as_ref().unwrap())
96                .expect("No namespace prefix bound");
97            write!(f, "</{}:{}>", *prefix, elem.name)?;
98        } else {
99            write!(f, "</{}>", elem.name)?;
100        }
101    }
102
103    Ok(())
104}
105
106impl fmt::Display for Element {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        fmt_elem(self, None, &HashMap::new(), f)
109    }
110}
111
112/// An iterator returning filtered child `Element`s of another `Element`
113pub struct ChildElements<'a, 'b> {
114    elems: slice::Iter<'a, Xml>,
115    name: &'b str,
116    ns: Option<&'b str>,
117}
118
119impl<'a, 'b> Iterator for ChildElements<'a, 'b> {
120    type Item = &'a Element;
121
122    fn next(&mut self) -> Option<&'a Element> {
123        let (name, ns) = (self.name, self.ns);
124        self.elems.by_ref().find_map(|child| {
125            if let Xml::ElementNode(ref elem) = *child {
126                if name == elem.name && ns == elem.ns.as_ref().map(|x| &x[..]) {
127                    return Some(elem);
128                }
129            }
130            None
131        })
132    }
133}
134
135impl Element {
136    /// Create a new `Element`, with specified name and namespace.
137    /// Attributes are specified as a `Vec` of `(name, namespace, value)` tuples.
138    pub fn new<A>(name: String, ns: Option<String>, attrs: A) -> Element
139    where
140        A: IntoIterator<Item = (String, Option<String>, String)>,
141    {
142        let mut prefixes = HashMap::with_capacity(2);
143        prefixes.insert(
144            "http://www.w3.org/XML/1998/namespace".to_owned(),
145            "xml".to_owned(),
146        );
147        prefixes.insert(
148            "http://www.w3.org/2000/xmlns/".to_owned(),
149            "xmlns".to_owned(),
150        );
151
152        let attributes: AttrMap<_, _> = attrs
153            .into_iter()
154            .map(|(name, ns, value)| ((name, ns), value))
155            .collect();
156
157        Element {
158            name,
159            ns: ns.clone(),
160            default_ns: ns,
161            prefixes,
162            attributes,
163            children: Vec::new(),
164        }
165    }
166
167    /// Returns the character and CDATA contained in the element.
168    pub fn content_str(&self) -> String {
169        let mut res = String::new();
170        for child in &self.children {
171            match *child {
172                Xml::ElementNode(ref elem) => res.push_str(&elem.content_str()),
173                Xml::CharacterNode(ref data) | Xml::CDATANode(ref data) => res.push_str(data),
174                _ => (),
175            }
176        }
177        res
178    }
179
180    /// Gets an attribute with the specified name and namespace. When an attribute with the
181    /// specified name does not exist `None` is returned.
182    pub fn get_attribute<'a>(&'a self, name: &str, ns: Option<&str>) -> Option<&'a str> {
183        self.attributes
184            .get(&(name.to_owned(), ns.map(|x| x.to_owned())))
185            .map(|x| &x[..])
186    }
187
188    /// Sets the attribute with the specified name and namespace.
189    /// Returns the original value.
190    pub fn set_attribute(
191        &mut self,
192        name: String,
193        ns: Option<String>,
194        value: String,
195    ) -> Option<String> {
196        self.attributes.insert((name, ns), value)
197    }
198
199    /// Remove the attribute with the specified name and namespace.
200    /// Returns the original value.
201    pub fn remove_attribute(&mut self, name: &str, ns: Option<&str>) -> Option<String> {
202        self.attributes
203            .remove(&(name.to_owned(), ns.map(|x| x.to_owned())))
204    }
205
206    /// Gets the first child `Element` with the specified name and namespace. When no child
207    /// with the specified name exists `None` is returned.
208    pub fn get_child<'a>(&'a self, name: &str, ns: Option<&str>) -> Option<&'a Element> {
209        self.get_children(name, ns).next()
210    }
211
212    /// Get all children `Element` with the specified name and namespace. When no child
213    /// with the specified name exists an empty vetor is returned.
214    pub fn get_children<'a, 'b>(
215        &'a self,
216        name: &'b str,
217        ns: Option<&'b str>,
218    ) -> ChildElements<'a, 'b> {
219        ChildElements {
220            elems: self.children.iter(),
221            name,
222            ns,
223        }
224    }
225
226    /// Appends a child element. Returns a reference to the added element.
227    pub fn tag(&mut self, child: Element) -> &mut Element {
228        self.children.push(Xml::ElementNode(child));
229        match self.children.last_mut() {
230            Some(Xml::ElementNode(ref mut elem)) => elem,
231            _ => unreachable!("Could not get reference to just added element!"),
232        }
233    }
234
235    /// Appends a child element. Returns a mutable reference to self.
236    pub fn tag_stay(&mut self, child: Element) -> &mut Element {
237        self.children.push(Xml::ElementNode(child));
238        self
239    }
240
241    /// Appends characters. Returns a mutable reference to self.
242    pub fn text(&mut self, text: String) -> &mut Element {
243        self.children.push(Xml::CharacterNode(text));
244        self
245    }
246
247    /// Appends CDATA. Returns a mutable reference to self.
248    pub fn cdata(&mut self, text: String) -> &mut Element {
249        self.children.push(Xml::CDATANode(text));
250        self
251    }
252
253    /// Appends a comment. Returns a mutable reference to self.
254    pub fn comment(&mut self, text: String) -> &mut Element {
255        self.children.push(Xml::CommentNode(text));
256        self
257    }
258
259    /// Appends processing information. Returns a mutable reference to self.
260    pub fn pi(&mut self, text: String) -> &mut Element {
261        self.children.push(Xml::PINode(text));
262        self
263    }
264}
265
266impl FromStr for Element {
267    type Err = BuilderError;
268    #[inline]
269    fn from_str(data: &str) -> Result<Element, BuilderError> {
270        let mut p = Parser::new();
271        let mut e = ElementBuilder::new();
272
273        p.feed_str(data);
274        p.find_map(|x| e.handle_event(x))
275            .unwrap_or(Err(BuilderError::NoElement))
276    }
277}
278
279#[cfg(test)]
280mod tests {
281    use super::Element;
282
283    #[test]
284    fn test_get_children() {
285        let elem: Element = "<a><b/><c/><b/></a>".parse().unwrap();
286        assert_eq!(
287            elem.get_children("b", None).collect::<Vec<_>>(),
288            vec![
289                &Element::new("b".to_owned(), None, vec![]),
290                &Element::new("b".to_owned(), None, vec![])
291            ],
292        );
293    }
294
295    #[test]
296    fn test_get_child() {
297        let elem: Element = "<a><b/><c/><b/></a>".parse().unwrap();
298        assert_eq!(
299            elem.get_child("b", None),
300            Some(&Element::new("b".to_owned(), None, vec![])),
301        );
302    }
303
304    #[test]
305    #[cfg(feature = "ordered_attrs")]
306    fn test_attribute_order_new() {
307        let input_attributes = vec![
308            ("href".to_owned(), None, "/".to_owned()),
309            ("title".to_owned(), None, "Home".to_owned()),
310            ("target".to_owned(), None, "_blank".to_owned()),
311        ];
312
313        // Run this 5 times to make it unlikely this test succeeds at random
314        for _ in 0..5 {
315            let elem = Element::new("a".to_owned(), None, input_attributes.clone());
316            for (expected, actual) in input_attributes.iter().zip(elem.attributes) {
317                assert_eq!(expected.0, (actual.0).0);
318                assert_eq!(expected.1, (actual.0).1);
319                assert_eq!(expected.2, actual.1);
320            }
321        }
322    }
323
324    #[test]
325    #[cfg(feature = "ordered_attrs")]
326    fn test_attribute_order_added() {
327        let input_attributes = vec![
328            ("href".to_owned(), None, "/".to_owned()),
329            ("title".to_owned(), None, "Home".to_owned()),
330            ("target".to_owned(), None, "_blank".to_owned()),
331        ];
332
333        // Run this 5 times to make it unlikely this test succeeds at random
334        for _ in 0..5 {
335            let mut elem = Element::new("a".to_owned(), None, vec![]);
336            for attr in &input_attributes {
337                elem.set_attribute(attr.0.clone(), attr.1.clone(), attr.2.clone());
338            }
339            for (expected, actual) in input_attributes.iter().zip(elem.attributes) {
340                assert_eq!(expected.0, (actual.0).0);
341                assert_eq!(expected.1, (actual.0).1);
342                assert_eq!(expected.2, actual.1);
343            }
344        }
345    }
346}